s4:dsdb: fix samdb_result_logon_hours() and don't hardcode units_per_week
[metze/samba/wip.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_errors.h"
28 #include "../lib/util/util_ldb.h"
29 #include "../lib/crypto/crypto.h"
30 #include "dsdb/samdb/samdb.h"
31 #include "libcli/security/security.h"
32 #include "librpc/gen_ndr/ndr_security.h"
33 #include "librpc/gen_ndr/ndr_misc.h"
34 #include "../libds/common/flags.h"
35 #include "dsdb/common/proto.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "param/param.h"
38 #include "libcli/auth/libcli_auth.h"
39 #include "librpc/gen_ndr/ndr_drsblobs.h"
40 #include "system/locale.h"
41 #include "lib/util/tsort.h"
42 #include "dsdb/common/util.h"
43 #include "lib/socket/socket.h"
44 #include "dsdb/samdb/ldb_modules/util.h"
45
46 /*
47   search the sam for the specified attributes in a specific domain, filter on
48   objectSid being in domain_sid.
49 */
50 int samdb_search_domain(struct ldb_context *sam_ldb,
51                         TALLOC_CTX *mem_ctx, 
52                         struct ldb_dn *basedn,
53                         struct ldb_message ***res,
54                         const char * const *attrs,
55                         const struct dom_sid *domain_sid,
56                         const char *format, ...)  _PRINTF_ATTRIBUTE(7,8)
57 {
58         va_list ap;
59         int i, count;
60
61         va_start(ap, format);
62         count = gendb_search_v(sam_ldb, mem_ctx, basedn,
63                                res, attrs, format, ap);
64         va_end(ap);
65
66         i=0;
67
68         while (i<count) {
69                 struct dom_sid *entry_sid;
70
71                 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
72
73                 if ((entry_sid == NULL) ||
74                     (!dom_sid_in_domain(domain_sid, entry_sid))) {
75                         /* Delete that entry from the result set */
76                         (*res)[i] = (*res)[count-1];
77                         count -= 1;
78                         talloc_free(entry_sid);
79                         continue;
80                 }
81                 talloc_free(entry_sid);
82                 i += 1;
83         }
84
85         return count;
86 }
87
88 /*
89   search the sam for a single string attribute in exactly 1 record
90 */
91 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
92                                   TALLOC_CTX *mem_ctx,
93                                   struct ldb_dn *basedn,
94                                   const char *attr_name,
95                                   const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
96 {
97         int count;
98         const char *attrs[2] = { NULL, NULL };
99         struct ldb_message **res = NULL;
100
101         attrs[0] = attr_name;
102
103         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
104         if (count > 1) {                
105                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
106                          attr_name, format, count));
107         }
108         if (count != 1) {
109                 talloc_free(res);
110                 return NULL;
111         }
112
113         return samdb_result_string(res[0], attr_name, NULL);
114 }
115
116 /*
117   search the sam for a single string attribute in exactly 1 record
118 */
119 const char *samdb_search_string(struct ldb_context *sam_ldb,
120                                 TALLOC_CTX *mem_ctx,
121                                 struct ldb_dn *basedn,
122                                 const char *attr_name,
123                                 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
124 {
125         va_list ap;
126         const char *str;
127
128         va_start(ap, format);
129         str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
130         va_end(ap);
131
132         return str;
133 }
134
135 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
136                                TALLOC_CTX *mem_ctx,
137                                struct ldb_dn *basedn,
138                                const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
139 {
140         va_list ap;
141         struct ldb_dn *ret;
142         struct ldb_message **res = NULL;
143         int count;
144
145         va_start(ap, format);
146         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
147         va_end(ap);
148
149         if (count != 1) return NULL;
150
151         ret = talloc_steal(mem_ctx, res[0]->dn);
152         talloc_free(res);
153
154         return ret;
155 }
156
157 /*
158   search the sam for a dom_sid attribute in exactly 1 record
159 */
160 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
161                                      TALLOC_CTX *mem_ctx,
162                                      struct ldb_dn *basedn,
163                                      const char *attr_name,
164                                      const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
165 {
166         va_list ap;
167         int count;
168         struct ldb_message **res;
169         const char *attrs[2] = { NULL, NULL };
170         struct dom_sid *sid;
171
172         attrs[0] = attr_name;
173
174         va_start(ap, format);
175         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
176         va_end(ap);
177         if (count > 1) {                
178                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
179                          attr_name, format, count));
180         }
181         if (count != 1) {
182                 talloc_free(res);
183                 return NULL;
184         }
185         sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
186         talloc_free(res);
187         return sid;     
188 }
189
190 /*
191   return the count of the number of records in the sam matching the query
192 */
193 int samdb_search_count(struct ldb_context *sam_ldb,
194                        struct ldb_dn *basedn,
195                        const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
196 {
197         va_list ap;
198         struct ldb_message **res;
199         const char *attrs[] = { NULL };
200         int ret;
201         TALLOC_CTX *tmp_ctx = talloc_new(sam_ldb);
202
203         va_start(ap, format);
204         ret = gendb_search_v(sam_ldb, tmp_ctx, basedn, &res, attrs, format, ap);
205         va_end(ap);
206         talloc_free(tmp_ctx);
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 samdb_result_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 samdb_result_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] = samdb_result_string(res[i], attr_name, NULL);
312         }
313         (*strs)[count] = NULL;
314
315         return count;
316 }
317
318 /*
319   pull a uint from a result set. 
320 */
321 unsigned int samdb_result_uint(const struct ldb_message *msg, const char *attr, unsigned int default_value)
322 {
323         return ldb_msg_find_attr_as_uint(msg, attr, default_value);
324 }
325
326 /*
327   pull a (signed) int64 from a result set. 
328 */
329 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
330 {
331         return ldb_msg_find_attr_as_int64(msg, attr, default_value);
332 }
333
334 /*
335   pull a string from a result set. 
336 */
337 const char *samdb_result_string(const struct ldb_message *msg, const char *attr, 
338                                 const char *default_value)
339 {
340         return ldb_msg_find_attr_as_string(msg, attr, default_value);
341 }
342
343 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
344                                const char *attr, struct ldb_dn *default_value)
345 {
346         struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
347         if (!ret_dn) {
348                 return default_value;
349         }
350         return ret_dn;
351 }
352
353 /*
354   pull a rid from a objectSid in a result set. 
355 */
356 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
357                                    const char *attr, uint32_t default_value)
358 {
359         struct dom_sid *sid;
360         uint32_t rid;
361
362         sid = samdb_result_dom_sid(mem_ctx, msg, attr);
363         if (sid == NULL) {
364                 return default_value;
365         }
366         rid = sid->sub_auths[sid->num_auths-1];
367         talloc_free(sid);
368         return rid;
369 }
370
371 /*
372   pull a dom_sid structure from a objectSid in a result set. 
373 */
374 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
375                                      const char *attr)
376 {
377         const struct ldb_val *v;
378         struct dom_sid *sid;
379         enum ndr_err_code ndr_err;
380         v = ldb_msg_find_ldb_val(msg, attr);
381         if (v == NULL) {
382                 return NULL;
383         }
384         sid = talloc(mem_ctx, struct dom_sid);
385         if (sid == NULL) {
386                 return NULL;
387         }
388         ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
389                                        (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
390         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
391                 talloc_free(sid);
392                 return NULL;
393         }
394         return sid;
395 }
396
397 /*
398   pull a guid structure from a objectGUID in a result set. 
399 */
400 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
401 {
402         const struct ldb_val *v;
403         struct GUID guid;
404         NTSTATUS status;
405
406         v = ldb_msg_find_ldb_val(msg, attr);
407         if (!v) return GUID_zero();
408
409         status = GUID_from_ndr_blob(v, &guid);
410         if (!NT_STATUS_IS_OK(status)) {
411                 return GUID_zero();
412         }
413
414         return guid;
415 }
416
417 /*
418   pull a sid prefix from a objectSid in a result set. 
419   this is used to find the domain sid for a user
420 */
421 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
422                                         const char *attr)
423 {
424         struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
425         if (!sid || sid->num_auths < 1) return NULL;
426         sid->num_auths--;
427         return sid;
428 }
429
430 /*
431   pull a NTTIME in a result set. 
432 */
433 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
434                            NTTIME default_value)
435 {
436         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
437 }
438
439 /*
440  * Windows stores 0 for lastLogoff.
441  * But when a MS DC return the lastLogoff (as Logoff Time)
442  * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
443  * cause windows 2008 and newer version to fail for SMB requests
444  */
445 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
446 {
447         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
448
449         if (ret == 0)
450                 ret = 0x7FFFFFFFFFFFFFFFULL;
451
452         return ret;
453 }
454
455 /*
456  * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
457  * indicate an account doesn't expire.
458  *
459  * When Windows initially creates an account, it sets
460  * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF).  However,
461  * when changing from an account having a specific expiration date to
462  * that account never expiring, it sets accountExpires = 0.
463  *
464  * Consolidate that logic here to allow clearer logic for account expiry in
465  * the rest of the code.
466  */
467 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
468 {
469         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
470                                                  0);
471
472         if (ret == 0)
473                 ret = 0x7FFFFFFFFFFFFFFFULL;
474
475         return ret;
476 }
477
478 /*
479   pull a uint64_t from a result set. 
480 */
481 uint64_t samdb_result_uint64(const struct ldb_message *msg, const char *attr,
482                              uint64_t default_value)
483 {
484         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
485 }
486
487
488 /*
489   construct the allow_password_change field from the PwdLastSet attribute and the 
490   domain password settings
491 */
492 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb, 
493                                           TALLOC_CTX *mem_ctx, 
494                                           struct ldb_dn *domain_dn, 
495                                           struct ldb_message *msg, 
496                                           const char *attr)
497 {
498         uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
499         int64_t minPwdAge;
500
501         if (attr_time == 0) {
502                 return 0;
503         }
504
505         minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
506
507         /* yes, this is a -= not a += as minPwdAge is stored as the negative
508            of the number of 100-nano-seconds */
509         attr_time -= minPwdAge;
510
511         return attr_time;
512 }
513
514 /*
515   construct the force_password_change field from the PwdLastSet
516   attribute, the userAccountControl and the domain password settings
517 */
518 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb, 
519                                           TALLOC_CTX *mem_ctx, 
520                                           struct ldb_dn *domain_dn, 
521                                           struct ldb_message *msg)
522 {
523         uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
524         uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
525         int64_t maxPwdAge;
526
527         /* Machine accounts don't expire, and there is a flag for 'no expiry' */
528         if (!(userAccountControl & UF_NORMAL_ACCOUNT)
529             || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
530                 return 0x7FFFFFFFFFFFFFFFULL;
531         }
532
533         if (attr_time == 0) {
534                 return 0;
535         }
536
537         maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
538         if (maxPwdAge == 0) {
539                 return 0x7FFFFFFFFFFFFFFFULL;
540         } else {
541                 attr_time -= maxPwdAge;
542         }
543
544         return attr_time;
545 }
546
547 /*
548   pull a samr_Password structutre from a result set. 
549 */
550 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
551 {
552         struct samr_Password *hash = NULL;
553         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
554         if (val && (val->length >= sizeof(hash->hash))) {
555                 hash = talloc(mem_ctx, struct samr_Password);
556                 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
557         }
558         return hash;
559 }
560
561 /*
562   pull an array of samr_Password structures from a result set.
563 */
564 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
565                            const char *attr, struct samr_Password **hashes)
566 {
567         unsigned int count, i;
568         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
569
570         *hashes = NULL;
571         if (!val) {
572                 return 0;
573         }
574         count = val->length / 16;
575         if (count == 0) {
576                 return 0;
577         }
578
579         *hashes = talloc_array(mem_ctx, struct samr_Password, count);
580         if (! *hashes) {
581                 return 0;
582         }
583
584         for (i=0;i<count;i++) {
585                 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
586         }
587
588         return count;
589 }
590
591 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg, 
592                                 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd) 
593 {
594         struct samr_Password *lmPwdHash, *ntPwdHash;
595         if (nt_pwd) {
596                 unsigned int num_nt;
597                 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
598                 if (num_nt == 0) {
599                         *nt_pwd = NULL;
600                 } else if (num_nt > 1) {
601                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
602                 } else {
603                         *nt_pwd = &ntPwdHash[0];
604                 }
605         }
606         if (lm_pwd) {
607                 /* Ensure that if we have turned off LM
608                  * authentication, that we never use the LM hash, even
609                  * if we store it */
610                 if (lp_lanman_auth(lp_ctx)) {
611                         unsigned int num_lm;
612                         num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
613                         if (num_lm == 0) {
614                                 *lm_pwd = NULL;
615                         } else if (num_lm > 1) {
616                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
617                         } else {
618                                 *lm_pwd = &lmPwdHash[0];
619                         }
620                 } else {
621                         *lm_pwd = NULL;
622                 }
623         }
624         return NT_STATUS_OK;
625 }
626
627 /*
628   pull a samr_LogonHours structutre from a result set. 
629 */
630 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
631 {
632         struct samr_LogonHours hours;
633         size_t units_per_week = 168;
634         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
635
636         ZERO_STRUCT(hours);
637
638         if (val) {
639                 units_per_week = val->length * 8;
640         }
641
642         hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
643         if (!hours.bits) {
644                 return hours;
645         }
646         hours.units_per_week = units_per_week;
647         memset(hours.bits, 0xFF, units_per_week/8);
648         if (val) {
649                 memcpy(hours.bits, val->data, val->length);
650         }
651
652         return hours;
653 }
654
655 /*
656   pull a set of account_flags from a result set. 
657
658   This requires that the attributes: 
659    pwdLastSet
660    userAccountControl
661   be included in 'msg'
662 */
663 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
664                                  struct ldb_message *msg, struct ldb_dn *domain_dn)
665 {
666         uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
667         uint32_t acct_flags = ds_uf2acb(userAccountControl);
668         NTTIME must_change_time;
669         NTTIME now;
670
671         must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx, 
672                                                               domain_dn, msg);
673
674         /* Test account expire time */
675         unix_to_nt_time(&now, time(NULL));
676         /* check for expired password */
677         if (must_change_time < now) {
678                 acct_flags |= ACB_PW_EXPIRED;
679         }
680         return acct_flags;
681 }
682
683 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
684                                                 struct ldb_message *msg,
685                                                 const char *attr)
686 {
687         struct lsa_BinaryString s;
688         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
689
690         ZERO_STRUCT(s);
691
692         if (!val) {
693                 return s;
694         }
695
696         s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
697         if (!s.array) {
698                 return s;
699         }
700         s.length = s.size = val->length;
701         memcpy(s.array, val->data, val->length);
702
703         return s;
704 }
705
706 /* Find an attribute, with a particular value */
707
708 /* The current callers of this function expect a very specific
709  * behaviour: In particular, objectClass subclass equivilance is not
710  * wanted.  This means that we should not lookup the schema for the
711  * comparison function */
712 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb, 
713                                                  const struct ldb_message *msg, 
714                                                  const char *name, const char *value)
715 {
716         unsigned int i;
717         struct ldb_message_element *el = ldb_msg_find_element(msg, name);
718
719         if (!el) {
720                 return NULL;
721         }
722
723         for (i=0;i<el->num_values;i++) {
724                 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
725                         return el;
726                 }
727         }
728
729         return NULL;
730 }
731
732 /*
733  * This is intended for use by the "password hash" module since there
734  * password changes can be specified through one message element with the
735  * new password (to set) and another one with the old password (to unset).
736  *
737  * The first which sets a password (new value) can have flags
738  * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
739  * for entries). The latter (old value) has always specified
740  * LDB_FLAG_MOD_DELETE.
741  *
742  * Returns LDB_ERR_NO_SUCH_ATTRIBUTE if the attribute which should be deleted
743  * doesn't contain only one value (this is the Windows Server behaviour)
744  * otherwise LDB_SUCCESS.
745  */
746 int samdb_msg_find_old_and_new_ldb_val(const struct ldb_message *msg,
747                                        const char *name,
748                                        const struct ldb_val **new_val,
749                                        const struct ldb_val **old_val)
750 {
751         unsigned int i;
752
753         *new_val = NULL;
754         *old_val = NULL;
755
756         if (msg == NULL) {
757                 return LDB_SUCCESS;
758         }
759
760         for (i = 0; i < msg->num_elements; i++) {
761                 if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
762                         if (msg->elements[i].flags == LDB_FLAG_MOD_DELETE) {
763                                 *old_val = &msg->elements[i].values[0];
764                         } else {
765                                 *new_val = &msg->elements[i].values[0];
766                         }
767                 }
768         }
769
770         return LDB_SUCCESS;
771 }
772
773 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
774 {
775         if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
776                 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
777         }
778         return LDB_SUCCESS;
779 }
780
781 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
782 {
783         struct ldb_message_element *el;
784
785         el = ldb_msg_find_element(msg, name);
786         if (el) {
787                 return LDB_SUCCESS;
788         }
789
790         return samdb_msg_add_string(ldb, msg, msg, name, set_value);
791 }
792
793
794
795 /*
796   add a string element to a message
797 */
798 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
799                          const char *attr_name, const char *str)
800 {
801         char *s = talloc_strdup(mem_ctx, str);
802         char *a = talloc_strdup(mem_ctx, attr_name);
803         if (s == NULL || a == NULL) {
804                 return LDB_ERR_OPERATIONS_ERROR;
805         }
806         return ldb_msg_add_string(msg, a, s);
807 }
808
809 /*
810   add a dom_sid element to a message
811 */
812 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
813                          const char *attr_name, struct dom_sid *sid)
814 {
815         struct ldb_val v;
816         enum ndr_err_code ndr_err;
817
818         ndr_err = ndr_push_struct_blob(&v, mem_ctx, 
819                                        lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
820                                        sid,
821                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
822         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
823                 return LDB_ERR_OPERATIONS_ERROR;
824         }
825         return ldb_msg_add_value(msg, attr_name, &v, NULL);
826 }
827
828
829 /*
830   add a delete element operation to a message
831 */
832 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
833                          const char *attr_name)
834 {
835         /* we use an empty replace rather than a delete, as it allows for 
836            dsdb_replace() to be used everywhere */
837         return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
838 }
839
840 /*
841   add a add attribute value to a message
842 */
843 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
844                          const char *attr_name, const char *value)
845 {
846         struct ldb_message_element *el;
847         char *a, *v;
848         int ret;
849         a = talloc_strdup(mem_ctx, attr_name);
850         if (a == NULL)
851                 return LDB_ERR_OPERATIONS_ERROR;
852         v = talloc_strdup(mem_ctx, value);
853         if (v == NULL)
854                 return LDB_ERR_OPERATIONS_ERROR;
855         ret = ldb_msg_add_string(msg, a, v);
856         if (ret != 0)
857                 return ret;
858         el = ldb_msg_find_element(msg, a);
859         if (el == NULL)
860                 return LDB_ERR_OPERATIONS_ERROR;
861         el->flags = LDB_FLAG_MOD_ADD;
862         return LDB_SUCCESS;
863 }
864
865 /*
866   add a delete attribute value to a message
867 */
868 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
869                          const char *attr_name, const char *value)
870 {
871         struct ldb_message_element *el;
872         char *a, *v;
873         int ret;
874         a = talloc_strdup(mem_ctx, attr_name);
875         if (a == NULL)
876                 return LDB_ERR_OPERATIONS_ERROR;
877         v = talloc_strdup(mem_ctx, value);
878         if (v == NULL)
879                 return LDB_ERR_OPERATIONS_ERROR;
880         ret = ldb_msg_add_string(msg, a, v);
881         if (ret != 0)
882                 return ret;
883         el = ldb_msg_find_element(msg, a);
884         if (el == NULL)
885                 return LDB_ERR_OPERATIONS_ERROR;
886         el->flags = LDB_FLAG_MOD_DELETE;
887         return LDB_SUCCESS;
888 }
889
890 /*
891   add a int element to a message
892 */
893 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
894                        const char *attr_name, int v)
895 {
896         const char *s = talloc_asprintf(mem_ctx, "%d", v);
897         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
898 }
899
900 /*
901   add a unsigned int element to a message
902 */
903 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
904                        const char *attr_name, unsigned int v)
905 {
906         return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
907 }
908
909 /*
910   add a (signed) int64_t element to a message
911 */
912 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
913                         const char *attr_name, int64_t v)
914 {
915         const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
916         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
917 }
918
919 /*
920   add a uint64_t element to a message
921 */
922 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
923                         const char *attr_name, uint64_t v)
924 {
925         return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
926 }
927
928 /*
929   add a samr_Password element to a message
930 */
931 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
932                        const char *attr_name, struct samr_Password *hash)
933 {
934         struct ldb_val val;
935         val.data = talloc_memdup(mem_ctx, hash->hash, 16);
936         if (!val.data) {
937                 return LDB_ERR_OPERATIONS_ERROR;
938         }
939         val.length = 16;
940         return ldb_msg_add_value(msg, attr_name, &val, NULL);
941 }
942
943 /*
944   add a samr_Password array to a message
945 */
946 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
947                          const char *attr_name, struct samr_Password *hashes,
948                          unsigned int count)
949 {
950         struct ldb_val val;
951         unsigned int i;
952         val.data = talloc_array_size(mem_ctx, 16, count);
953         val.length = count*16;
954         if (!val.data) {
955                 return LDB_ERR_OPERATIONS_ERROR;
956         }
957         for (i=0;i<count;i++) {
958                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
959         }
960         return ldb_msg_add_value(msg, attr_name, &val, NULL);
961 }
962
963 /*
964   add a acct_flags element to a message
965 */
966 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
967                              const char *attr_name, uint32_t v)
968 {
969         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
970 }
971
972 /*
973   add a logon_hours element to a message
974 */
975 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
976                               const char *attr_name, struct samr_LogonHours *hours)
977 {
978         struct ldb_val val;
979         val.length = hours->units_per_week / 8;
980         val.data = hours->bits;
981         return ldb_msg_add_value(msg, attr_name, &val, NULL);
982 }
983
984 /*
985   add a parameters element to a message
986 */
987 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
988                              const char *attr_name, struct lsa_BinaryString *parameters)
989 {
990         struct ldb_val val;
991         val.length = parameters->length;
992         val.data = (uint8_t *)parameters->array;
993         return ldb_msg_add_value(msg, attr_name, &val, NULL);
994 }
995 /*
996   add a general value element to a message
997 */
998 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
999                               const char *attr_name, const struct ldb_val *val)
1000 {
1001         return ldb_msg_add_value(msg, attr_name, val, NULL);
1002 }
1003
1004 /*
1005   sets a general value element to a message
1006 */
1007 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1008                         const char *attr_name, const struct ldb_val *val)
1009 {
1010         struct ldb_message_element *el;
1011
1012         el = ldb_msg_find_element(msg, attr_name);
1013         if (el) {
1014                 el->num_values = 0;
1015         }
1016         return ldb_msg_add_value(msg, attr_name, val, NULL);
1017 }
1018
1019 /*
1020   set a string element in a message
1021 */
1022 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1023                          const char *attr_name, const char *str)
1024 {
1025         struct ldb_message_element *el;
1026
1027         el = ldb_msg_find_element(msg, attr_name);
1028         if (el) {
1029                 el->num_values = 0;
1030         }
1031         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
1032 }
1033
1034 /*
1035  * Handle ldb_request in transaction
1036  */
1037 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1038                                         struct ldb_request *req)
1039 {
1040         int ret;
1041
1042         ret = ldb_transaction_start(sam_ldb);
1043         if (ret != LDB_SUCCESS) {
1044                 return ret;
1045         }
1046
1047         ret = ldb_request(sam_ldb, req);
1048         if (ret == LDB_SUCCESS) {
1049                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1050         }
1051
1052         if (ret == LDB_SUCCESS) {
1053                 return ldb_transaction_commit(sam_ldb);
1054         }
1055         ldb_transaction_cancel(sam_ldb);
1056
1057         return ret;
1058 }
1059
1060 /*
1061   return a default security descriptor
1062 */
1063 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1064 {
1065         struct security_descriptor *sd;
1066
1067         sd = security_descriptor_initialise(mem_ctx);
1068
1069         return sd;
1070 }
1071
1072 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) 
1073 {
1074         struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1075         struct ldb_dn *aggregate_dn;
1076         if (!schema_dn) {
1077                 return NULL;
1078         }
1079
1080         aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1081         if (!aggregate_dn) {
1082                 return NULL;
1083         }
1084         if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1085                 return NULL;
1086         }
1087         return aggregate_dn;
1088 }
1089
1090 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1091 {
1092         struct ldb_dn *new_dn;
1093
1094         new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1095         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1096                 talloc_free(new_dn);
1097                 return NULL;
1098         }
1099         return new_dn;
1100 }
1101
1102 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1103 {
1104        struct ldb_dn *new_dn;
1105
1106        new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1107        if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1108                talloc_free(new_dn);
1109                return NULL;
1110        }
1111        return new_dn;
1112 }
1113
1114 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1115 {
1116         struct ldb_dn *new_dn;
1117
1118         new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1119         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1120                 talloc_free(new_dn);
1121                 return NULL;
1122         }
1123         return new_dn;
1124 }
1125
1126 /*
1127   work out the domain sid for the current open ldb
1128 */
1129 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1130 {
1131         TALLOC_CTX *tmp_ctx;
1132         const struct dom_sid *domain_sid;
1133         const char *attrs[] = {
1134                 "objectSid",
1135                 NULL
1136         };
1137         struct ldb_result *res;
1138         int ret;
1139
1140         /* see if we have a cached copy */
1141         domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1142         if (domain_sid) {
1143                 return domain_sid;
1144         }
1145
1146         tmp_ctx = talloc_new(ldb);
1147         if (tmp_ctx == NULL) {
1148                 goto failed;
1149         }
1150
1151         ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1152
1153         if (ret != LDB_SUCCESS) {
1154                 goto failed;
1155         }
1156
1157         if (res->count != 1) {
1158                 goto failed;
1159         }
1160
1161         domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1162         if (domain_sid == NULL) {
1163                 goto failed;
1164         }
1165
1166         /* cache the domain_sid in the ldb */
1167         if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1168                 goto failed;
1169         }
1170
1171         talloc_steal(ldb, domain_sid);
1172         talloc_free(tmp_ctx);
1173
1174         return domain_sid;
1175
1176 failed:
1177         talloc_free(tmp_ctx);
1178         return NULL;
1179 }
1180
1181 /*
1182   get domain sid from cache
1183 */
1184 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1185 {
1186         return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1187 }
1188
1189 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1190 {
1191         TALLOC_CTX *tmp_ctx;
1192         struct dom_sid *dom_sid_new;
1193         struct dom_sid *dom_sid_old;
1194
1195         /* see if we have a cached copy */
1196         dom_sid_old = talloc_get_type(ldb_get_opaque(ldb, 
1197                                                      "cache.domain_sid"), struct dom_sid);
1198
1199         tmp_ctx = talloc_new(ldb);
1200         if (tmp_ctx == NULL) {
1201                 goto failed;
1202         }
1203
1204         dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1205         if (!dom_sid_new) {
1206                 goto failed;
1207         }
1208
1209         /* cache the domain_sid in the ldb */
1210         if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1211                 goto failed;
1212         }
1213
1214         talloc_steal(ldb, dom_sid_new);
1215         talloc_free(tmp_ctx);
1216         talloc_free(dom_sid_old);
1217
1218         return true;
1219
1220 failed:
1221         DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1222         talloc_free(tmp_ctx);
1223         return false;
1224 }
1225
1226 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1227 {
1228         TALLOC_CTX *tmp_ctx;
1229         struct ldb_dn *ntds_settings_dn_new;
1230         struct ldb_dn *ntds_settings_dn_old;
1231
1232         /* see if we have a cached copy */
1233         ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb, 
1234                                                               "cache.ntds_settings_dn"), struct ldb_dn);
1235
1236         tmp_ctx = talloc_new(ldb);
1237         if (tmp_ctx == NULL) {
1238                 goto failed;
1239         }
1240
1241         ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1242         if (!ntds_settings_dn_new) {
1243                 goto failed;
1244         }
1245
1246         /* cache the domain_sid in the ldb */
1247         if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1248                 goto failed;
1249         }
1250
1251         talloc_steal(ldb, ntds_settings_dn_new);
1252         talloc_free(tmp_ctx);
1253         talloc_free(ntds_settings_dn_old);
1254
1255         return true;
1256
1257 failed:
1258         DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1259         talloc_free(tmp_ctx);
1260         return false;
1261 }
1262
1263 /* Obtain the short name of the flexible single master operator
1264  * (FSMO), such as the PDC Emulator */
1265 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
1266                              const char *attr)
1267 {
1268         /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1269         struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1270         const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1271         const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1272
1273         if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1274                 /* Ensure this matches the format.  This gives us a
1275                  * bit more confidence that a 'cn' value will be a
1276                  * ascii string */
1277                 return NULL;
1278         }
1279         if (val) {
1280                 return (char *)val->data;
1281         }
1282         return NULL;
1283 }
1284
1285 /*
1286   work out the ntds settings dn for the current open ldb
1287 */
1288 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1289 {
1290         TALLOC_CTX *tmp_ctx;
1291         const char *root_attrs[] = { "dsServiceName", NULL };
1292         int ret;
1293         struct ldb_result *root_res;
1294         struct ldb_dn *settings_dn;
1295
1296         /* see if we have a cached copy */
1297         settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
1298         if (settings_dn) {
1299                 return settings_dn;
1300         }
1301
1302         tmp_ctx = talloc_new(ldb);
1303         if (tmp_ctx == NULL) {
1304                 goto failed;
1305         }
1306
1307         ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1308         if (ret) {
1309                 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n", 
1310                          ldb_errstring(ldb)));
1311                 goto failed;
1312         }
1313
1314         if (root_res->count != 1) {
1315                 goto failed;
1316         }
1317
1318         settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1319
1320         /* cache the domain_sid in the ldb */
1321         if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1322                 goto failed;
1323         }
1324
1325         talloc_steal(ldb, settings_dn);
1326         talloc_free(tmp_ctx);
1327
1328         return settings_dn;
1329
1330 failed:
1331         DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1332         talloc_free(tmp_ctx);
1333         return NULL;
1334 }
1335
1336 /*
1337   work out the ntds settings invocationId for the current open ldb
1338 */
1339 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1340 {
1341         TALLOC_CTX *tmp_ctx;
1342         const char *attrs[] = { "invocationId", NULL };
1343         int ret;
1344         struct ldb_result *res;
1345         struct GUID *invocation_id;
1346
1347         /* see if we have a cached copy */
1348         invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1349         if (invocation_id) {
1350                 return invocation_id;
1351         }
1352
1353         tmp_ctx = talloc_new(ldb);
1354         if (tmp_ctx == NULL) {
1355                 goto failed;
1356         }
1357
1358         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1359         if (ret) {
1360                 goto failed;
1361         }
1362
1363         if (res->count != 1) {
1364                 goto failed;
1365         }
1366
1367         invocation_id = talloc(tmp_ctx, struct GUID);
1368         if (!invocation_id) {
1369                 goto failed;
1370         }
1371
1372         *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1373
1374         /* cache the domain_sid in the ldb */
1375         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1376                 goto failed;
1377         }
1378
1379         talloc_steal(ldb, invocation_id);
1380         talloc_free(tmp_ctx);
1381
1382         return invocation_id;
1383
1384 failed:
1385         DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1386         talloc_free(tmp_ctx);
1387         return NULL;
1388 }
1389
1390 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1391 {
1392         TALLOC_CTX *tmp_ctx;
1393         struct GUID *invocation_id_new;
1394         struct GUID *invocation_id_old;
1395
1396         /* see if we have a cached copy */
1397         invocation_id_old = (struct GUID *)ldb_get_opaque(ldb, 
1398                                                          "cache.invocation_id");
1399
1400         tmp_ctx = talloc_new(ldb);
1401         if (tmp_ctx == NULL) {
1402                 goto failed;
1403         }
1404
1405         invocation_id_new = talloc(tmp_ctx, struct GUID);
1406         if (!invocation_id_new) {
1407                 goto failed;
1408         }
1409
1410         *invocation_id_new = *invocation_id_in;
1411
1412         /* cache the domain_sid in the ldb */
1413         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1414                 goto failed;
1415         }
1416
1417         talloc_steal(ldb, invocation_id_new);
1418         talloc_free(tmp_ctx);
1419         talloc_free(invocation_id_old);
1420
1421         return true;
1422
1423 failed:
1424         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1425         talloc_free(tmp_ctx);
1426         return false;
1427 }
1428
1429 /*
1430   work out the ntds settings objectGUID for the current open ldb
1431 */
1432 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1433 {
1434         TALLOC_CTX *tmp_ctx;
1435         const char *attrs[] = { "objectGUID", NULL };
1436         int ret;
1437         struct ldb_result *res;
1438         struct GUID *ntds_guid;
1439
1440         /* see if we have a cached copy */
1441         ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1442         if (ntds_guid) {
1443                 return ntds_guid;
1444         }
1445
1446         tmp_ctx = talloc_new(ldb);
1447         if (tmp_ctx == NULL) {
1448                 goto failed;
1449         }
1450
1451         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1452         if (ret) {
1453                 goto failed;
1454         }
1455
1456         if (res->count != 1) {
1457                 goto failed;
1458         }
1459
1460         ntds_guid = talloc(tmp_ctx, struct GUID);
1461         if (!ntds_guid) {
1462                 goto failed;
1463         }
1464
1465         *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1466
1467         /* cache the domain_sid in the ldb */
1468         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1469                 goto failed;
1470         }
1471
1472         talloc_steal(ldb, ntds_guid);
1473         talloc_free(tmp_ctx);
1474
1475         return ntds_guid;
1476
1477 failed:
1478         DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1479         talloc_free(tmp_ctx);
1480         return NULL;
1481 }
1482
1483 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1484 {
1485         TALLOC_CTX *tmp_ctx;
1486         struct GUID *ntds_guid_new;
1487         struct GUID *ntds_guid_old;
1488
1489         /* see if we have a cached copy */
1490         ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1491
1492         tmp_ctx = talloc_new(ldb);
1493         if (tmp_ctx == NULL) {
1494                 goto failed;
1495         }
1496
1497         ntds_guid_new = talloc(tmp_ctx, struct GUID);
1498         if (!ntds_guid_new) {
1499                 goto failed;
1500         }
1501
1502         *ntds_guid_new = *ntds_guid_in;
1503
1504         /* cache the domain_sid in the ldb */
1505         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1506                 goto failed;
1507         }
1508
1509         talloc_steal(ldb, ntds_guid_new);
1510         talloc_free(tmp_ctx);
1511         talloc_free(ntds_guid_old);
1512
1513         return true;
1514
1515 failed:
1516         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1517         talloc_free(tmp_ctx);
1518         return false;
1519 }
1520
1521 /*
1522   work out the server dn for the current open ldb
1523 */
1524 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1525 {
1526         return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1527 }
1528
1529 /*
1530   work out the server dn for the current open ldb
1531 */
1532 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1533 {
1534         struct ldb_dn *server_dn;
1535         struct ldb_dn *servers_dn;
1536         struct ldb_dn *server_site_dn;
1537
1538         /* TODO: there must be a saner way to do this!! */
1539         server_dn = samdb_server_dn(ldb, mem_ctx);
1540         if (!server_dn) return NULL;
1541
1542         servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1543         talloc_free(server_dn);
1544         if (!servers_dn) return NULL;
1545
1546         server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1547         talloc_free(servers_dn);
1548
1549         return server_site_dn;
1550 }
1551
1552 /*
1553   find a 'reference' DN that points at another object
1554   (eg. serverReference, rIDManagerReference etc)
1555  */
1556 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1557                        const char *attribute, struct ldb_dn **dn)
1558 {
1559         const char *attrs[2];
1560         struct ldb_result *res;
1561         int ret;
1562
1563         attrs[0] = attribute;
1564         attrs[1] = NULL;
1565
1566         ret = ldb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, NULL);
1567         if (ret != LDB_SUCCESS) {
1568                 return ret;
1569         }
1570         if (res->count != 1) {
1571                 talloc_free(res);
1572                 return LDB_ERR_NO_SUCH_OBJECT;
1573         }
1574
1575         *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1576         if (!*dn) {
1577                 talloc_free(res);
1578                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1579         }
1580
1581         talloc_free(res);
1582         return LDB_SUCCESS;
1583 }
1584
1585 /*
1586   find our machine account via the serverReference attribute in the
1587   server DN
1588  */
1589 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1590 {
1591         struct ldb_dn *server_dn;
1592         int ret;
1593
1594         server_dn = samdb_server_dn(ldb, mem_ctx);
1595         if (server_dn == NULL) {
1596                 return LDB_ERR_NO_SUCH_OBJECT;
1597         }
1598
1599         ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1600         talloc_free(server_dn);
1601
1602         return ret;
1603 }
1604
1605 /*
1606   find the RID Manager$ DN via the rIDManagerReference attribute in the
1607   base DN
1608  */
1609 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1610 {
1611         return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1612                                   "rIDManagerReference", dn);
1613 }
1614
1615 /*
1616   find the RID Set DN via the rIDSetReferences attribute in our
1617   machine account DN
1618  */
1619 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1620 {
1621         struct ldb_dn *server_ref_dn;
1622         int ret;
1623
1624         ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1625         if (ret != LDB_SUCCESS) {
1626                 return ret;
1627         }
1628         ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1629         talloc_free(server_ref_dn);
1630         return ret;
1631 }
1632
1633 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1634 {
1635         const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1636                                                                             mem_ctx));
1637
1638         if (val == NULL) {
1639                 return NULL;
1640         }
1641
1642         return (const char *) val->data;
1643 }
1644
1645 /*
1646  * Finds the client site by using the client's IP address.
1647  * The "subnet_name" returns the name of the subnet if parameter != NULL
1648  */
1649 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1650                                    const char *ip_address, char **subnet_name)
1651 {
1652         const char *attrs[] = { "cn", "siteObject", NULL };
1653         struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1654         struct ldb_result *res;
1655         const struct ldb_val *val;
1656         const char *site_name = NULL, *l_subnet_name = NULL;
1657         const char *allow_list[2] = { NULL, NULL };
1658         unsigned int i, count;
1659         int cnt, ret;
1660
1661         /*
1662          * if we don't have a client ip e.g. ncalrpc
1663          * the server site is the client site
1664          */
1665         if (ip_address == NULL) {
1666                 return samdb_server_site_name(ldb, mem_ctx);
1667         }
1668
1669         sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1670         if (sites_container_dn == NULL) {
1671                 return NULL;
1672         }
1673
1674         subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1675         if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1676                 talloc_free(sites_container_dn);
1677                 talloc_free(subnets_dn);
1678                 return NULL;
1679         }
1680
1681         ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1682                          attrs, NULL);
1683         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1684                 count = 0;
1685         } else if (ret != LDB_SUCCESS) {
1686                 talloc_free(sites_container_dn);
1687                 talloc_free(subnets_dn);
1688                 return NULL;
1689         } else {
1690                 count = res->count;
1691         }
1692
1693         for (i = 0; i < count; i++) {
1694                 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1695                                                             NULL);
1696
1697                 allow_list[0] = l_subnet_name;
1698
1699                 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1700                         sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1701                                                            res->msgs[i],
1702                                                            "siteObject");
1703                         if (sites_dn == NULL) {
1704                                 /* No reference, maybe another subnet matches */
1705                                 continue;
1706                         }
1707
1708                         /* "val" cannot be NULL here since "sites_dn" != NULL */
1709                         val = ldb_dn_get_rdn_val(sites_dn);
1710                         site_name = talloc_strdup(mem_ctx,
1711                                                   (const char *) val->data);
1712
1713                         talloc_free(sites_dn);
1714
1715                         break;
1716                 }
1717         }
1718
1719         if (site_name == NULL) {
1720                 /* This is the Windows Server fallback rule: when no subnet
1721                  * exists and we have only one site available then use it (it
1722                  * is for sure the same as our server site). If more sites do
1723                  * exist then we don't know which one to use and set the site
1724                  * name to "". */
1725                 cnt = samdb_search_count(ldb, sites_container_dn,
1726                                          "(objectClass=site)");
1727                 if (cnt == 1) {
1728                         site_name = samdb_server_site_name(ldb, mem_ctx);
1729                 } else {
1730                         site_name = talloc_strdup(mem_ctx, "");
1731                 }
1732                 l_subnet_name = NULL;
1733         }
1734
1735         if (subnet_name != NULL) {
1736                 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1737         }
1738
1739         talloc_free(sites_container_dn);
1740         talloc_free(subnets_dn);
1741         talloc_free(res);
1742
1743         return site_name;
1744 }
1745
1746 /*
1747   work out if we are the PDC for the domain of the current open ldb
1748 */
1749 bool samdb_is_pdc(struct ldb_context *ldb)
1750 {
1751         const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1752         int ret;
1753         struct ldb_result *dom_res;
1754         TALLOC_CTX *tmp_ctx;
1755         bool is_pdc;
1756         struct ldb_dn *pdc;
1757
1758         tmp_ctx = talloc_new(ldb);
1759         if (tmp_ctx == NULL) {
1760                 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1761                 return false;
1762         }
1763
1764         ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1765         if (ret) {
1766                 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n", 
1767                          ldb_dn_get_linearized(ldb_get_default_basedn(ldb)), 
1768                          ldb_errstring(ldb)));
1769                 goto failed;
1770         }
1771         if (dom_res->count != 1) {
1772                 goto failed;
1773         }
1774
1775         pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1776
1777         if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1778                 is_pdc = true;
1779         } else {
1780                 is_pdc = false;
1781         }
1782
1783         talloc_free(tmp_ctx);
1784
1785         return is_pdc;
1786
1787 failed:
1788         DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1789         talloc_free(tmp_ctx);
1790         return false;
1791 }
1792
1793 /*
1794   work out if we are a Global Catalog server for the domain of the current open ldb
1795 */
1796 bool samdb_is_gc(struct ldb_context *ldb)
1797 {
1798         const char *attrs[] = { "options", NULL };
1799         int ret, options;
1800         struct ldb_result *res;
1801         TALLOC_CTX *tmp_ctx;
1802
1803         tmp_ctx = talloc_new(ldb);
1804         if (tmp_ctx == NULL) {
1805                 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1806                 return false;
1807         }
1808
1809         /* Query cn=ntds settings,.... */
1810         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1811         if (ret) {
1812                 talloc_free(tmp_ctx);
1813                 return false;
1814         }
1815         if (res->count != 1) {
1816                 talloc_free(tmp_ctx);
1817                 return false;
1818         }
1819
1820         options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1821         talloc_free(tmp_ctx);
1822
1823         /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1824         if (options & 0x000000001) {
1825                 return true;
1826         }
1827         return false;
1828 }
1829
1830 /* Find a domain object in the parents of a particular DN.  */
1831 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1832                                    struct ldb_dn **parent_dn, const char **errstring)
1833 {
1834         TALLOC_CTX *local_ctx;
1835         struct ldb_dn *sdn = dn;
1836         struct ldb_result *res = NULL;
1837         int ret = 0;
1838         const char *attrs[] = { NULL };
1839
1840         local_ctx = talloc_new(mem_ctx);
1841         if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1842
1843         while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1844                 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1845                                  "(|(objectClass=domain)(objectClass=builtinDomain))");
1846                 if (ret == LDB_SUCCESS) {
1847                         if (res->count == 1) {
1848                                 break;
1849                         }
1850                 } else {
1851                         break;
1852                 }
1853         }
1854
1855         if (ret != LDB_SUCCESS) {
1856                 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1857                                              ldb_dn_get_linearized(dn),
1858                                              ldb_dn_get_linearized(sdn),
1859                                              ldb_errstring(ldb));
1860                 talloc_free(local_ctx);
1861                 return ret;
1862         }
1863         if (res->count != 1) {
1864                 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1865                                              ldb_dn_get_linearized(dn));
1866                 DEBUG(0,(__location__ ": %s\n", *errstring));
1867                 talloc_free(local_ctx);
1868                 return LDB_ERR_CONSTRAINT_VIOLATION;
1869         }
1870
1871         *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1872         talloc_free(local_ctx);
1873         return ret;
1874 }
1875
1876
1877 /*
1878  * Performs checks on a user password (plaintext UNIX format - attribute
1879  * "password"). The remaining parameters have to be extracted from the domain
1880  * object in the AD.
1881  *
1882  * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
1883  */
1884 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
1885                                                 const uint32_t pwdProperties,
1886                                                 const uint32_t minPwdLength)
1887 {
1888         /* checks if the "minPwdLength" property is satisfied */
1889         if (minPwdLength > password->length)
1890                 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
1891
1892         /* checks the password complexity */
1893         if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
1894                         && (password->data != NULL)
1895                         && (!check_password_quality((const char *) password->data)))
1896                 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
1897
1898         return SAMR_VALIDATION_STATUS_SUCCESS;
1899 }
1900
1901 /*
1902  * Callback for "samdb_set_password" password change
1903  */
1904 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
1905 {
1906         int ret;
1907
1908         if (!ares) {
1909                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1910         }
1911
1912         if (ares->error != LDB_SUCCESS) {
1913                 ret = ares->error;
1914                 req->context = talloc_steal(req,
1915                                             ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
1916                 talloc_free(ares);
1917                 return ldb_request_done(req, ret);
1918         }
1919
1920         if (ares->type != LDB_REPLY_DONE) {
1921                 talloc_free(ares);
1922                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1923         }
1924
1925         req->context = talloc_steal(req,
1926                                     ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
1927         talloc_free(ares);
1928         return ldb_request_done(req, LDB_SUCCESS);
1929 }
1930
1931 /*
1932  * Sets the user password using plaintext UTF16 (attribute "new_password") or
1933  * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
1934  * as parameter if it's a user change or not ("userChange"). The "rejectReason"
1935  * gives some more informations if the changed failed.
1936  *
1937  * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
1938  *   NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
1939  *   NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
1940  */
1941 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1942                             struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
1943                             const DATA_BLOB *new_password,
1944                             struct samr_Password *lmNewHash,
1945                             struct samr_Password *ntNewHash,
1946                             bool user_change,
1947                             enum samPwdChangeReason *reject_reason,
1948                             struct samr_DomInfo1 **_dominfo)
1949 {
1950         struct ldb_message *msg;
1951         struct ldb_message_element *el;
1952         struct ldb_request *req;
1953         struct dsdb_control_password_change_status *pwd_stat = NULL;
1954         int ret;
1955         NTSTATUS status;
1956
1957 #define CHECK_RET(x) \
1958         if (x != LDB_SUCCESS) { \
1959                 talloc_free(msg); \
1960                 return NT_STATUS_NO_MEMORY; \
1961         }
1962
1963         msg = ldb_msg_new(mem_ctx);
1964         if (msg == NULL) {
1965                 return NT_STATUS_NO_MEMORY;
1966         }
1967         msg->dn = user_dn;
1968         if ((new_password != NULL)
1969                         && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
1970                 /* we have the password as plaintext UTF16 */
1971                 CHECK_RET(samdb_msg_add_value(ldb, mem_ctx, msg,
1972                         "clearTextPassword", new_password));
1973                 el = ldb_msg_find_element(msg, "clearTextPassword");
1974                 el->flags = LDB_FLAG_MOD_REPLACE;
1975         } else if ((new_password == NULL)
1976                         && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
1977                 /* we have a password as LM and/or NT hash */
1978                 if (lmNewHash != NULL) {
1979                         CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
1980                                 "dBCSPwd", lmNewHash));
1981                         el = ldb_msg_find_element(msg, "dBCSPwd");
1982                         el->flags = LDB_FLAG_MOD_REPLACE;
1983                 }
1984                 if (ntNewHash != NULL) {
1985                         CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
1986                                 "unicodePwd", ntNewHash));
1987                         el = ldb_msg_find_element(msg, "unicodePwd");
1988                         el->flags = LDB_FLAG_MOD_REPLACE;
1989                 }
1990         } else {
1991                 /* the password wasn't specified correctly */
1992                 talloc_free(msg);
1993                 return NT_STATUS_INVALID_PARAMETER;
1994         }
1995
1996         /* build modify request */
1997         ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
1998                                 samdb_set_password_callback, NULL);
1999         if (ret != LDB_SUCCESS) {
2000                 talloc_free(msg);
2001                 return NT_STATUS_NO_MEMORY;
2002         }
2003
2004         if (user_change) {
2005                 /* a user password change and we've checked already the old
2006                  * password somewhere else (callers responsability) */
2007                 ret = ldb_request_add_control(req,
2008                                               DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID,
2009                                               true, NULL);
2010                 if (ret != LDB_SUCCESS) {
2011                         talloc_free(req);
2012                         talloc_free(msg);
2013                         return NT_STATUS_NO_MEMORY;
2014                 }
2015         }
2016         ret = ldb_request_add_control(req,
2017                                       DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2018                                       true, NULL);
2019         if (ret != LDB_SUCCESS) {
2020                 talloc_free(req);
2021                 talloc_free(msg);
2022                 return NT_STATUS_NO_MEMORY;
2023         }
2024         ret = ldb_request_add_control(req,
2025                                       DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2026                                       true, NULL);
2027         if (ret != LDB_SUCCESS) {
2028                 talloc_free(req);
2029                 talloc_free(msg);
2030                 return NT_STATUS_NO_MEMORY;
2031         }
2032
2033         ret = dsdb_autotransaction_request(ldb, req);
2034
2035         if (req->context != NULL) {
2036                 pwd_stat = talloc_steal(mem_ctx,
2037                                         ((struct ldb_control *)req->context)->data);
2038         }
2039
2040         talloc_free(req);
2041         talloc_free(msg);
2042
2043         /* Sets the domain info (if requested) */
2044         if (_dominfo != NULL) {
2045                 struct samr_DomInfo1 *dominfo;
2046
2047                 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2048                 if (dominfo == NULL) {
2049                         return NT_STATUS_NO_MEMORY;
2050                 }
2051
2052                 if (pwd_stat != NULL) {
2053                         dominfo->min_password_length     = pwd_stat->domain_data.minPwdLength;
2054                         dominfo->password_properties     = pwd_stat->domain_data.pwdProperties;
2055                         dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2056                         dominfo->max_password_age        = pwd_stat->domain_data.maxPwdAge;
2057                         dominfo->min_password_age        = pwd_stat->domain_data.minPwdAge;
2058                 }
2059
2060                 *_dominfo = dominfo;
2061         }
2062
2063         if (reject_reason != NULL) {
2064                 if (pwd_stat != NULL) {
2065                         *reject_reason = pwd_stat->reject_reason;
2066                 } else {
2067                         *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2068                 }
2069         }
2070
2071         if (pwd_stat != NULL) {
2072                 talloc_free(pwd_stat);
2073         }
2074
2075         /* TODO: Error results taken from "password_hash" module. Are they
2076            correct? */
2077         if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
2078                 status = NT_STATUS_WRONG_PASSWORD;
2079         } else if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2080                 status = NT_STATUS_PASSWORD_RESTRICTION;
2081         } else if (ret != LDB_SUCCESS) {
2082                 status = NT_STATUS_UNSUCCESSFUL;
2083         } else {
2084                 status = NT_STATUS_OK;
2085         }
2086
2087         return status;
2088 }
2089
2090 /*
2091  * Sets the user password using plaintext UTF16 (attribute "new_password") or
2092  * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2093  * as parameter if it's a user change or not ("userChange"). The "rejectReason"
2094  * gives some more informations if the changed failed.
2095  *
2096  * This wrapper function for "samdb_set_password" takes a SID as input rather
2097  * than a user DN.
2098  *
2099  * This call encapsulates a new LDB transaction for changing the password;
2100  * therefore the user hasn't to start a new one.
2101  *
2102  * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2103  *   NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2104  *   NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2105  */
2106 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2107                                 const struct dom_sid *user_sid,
2108                                 const DATA_BLOB *new_password,
2109                                 struct samr_Password *lmNewHash, 
2110                                 struct samr_Password *ntNewHash,
2111                                 bool user_change,
2112                                 enum samPwdChangeReason *reject_reason,
2113                                 struct samr_DomInfo1 **_dominfo) 
2114 {
2115         NTSTATUS nt_status;
2116         struct ldb_dn *user_dn;
2117         int ret;
2118
2119         ret = ldb_transaction_start(ldb);
2120         if (ret != LDB_SUCCESS) {
2121                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2122                 return NT_STATUS_TRANSACTION_ABORTED;
2123         }
2124
2125         user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2126                                   "(&(objectSid=%s)(objectClass=user))", 
2127                                   ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2128         if (!user_dn) {
2129                 ldb_transaction_cancel(ldb);
2130                 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2131                           dom_sid_string(mem_ctx, user_sid)));
2132                 return NT_STATUS_NO_SUCH_USER;
2133         }
2134
2135         nt_status = samdb_set_password(ldb, mem_ctx,
2136                                        user_dn, NULL,
2137                                        new_password,
2138                                        lmNewHash, ntNewHash,
2139                                        user_change,
2140                                        reject_reason, _dominfo);
2141         if (!NT_STATUS_IS_OK(nt_status)) {
2142                 ldb_transaction_cancel(ldb);
2143                 talloc_free(user_dn);
2144                 return nt_status;
2145         }
2146
2147         ret = ldb_transaction_commit(ldb);
2148         if (ret != LDB_SUCCESS) {
2149                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2150                          ldb_dn_get_linearized(user_dn),
2151                          ldb_errstring(ldb)));
2152                 talloc_free(user_dn);
2153                 return NT_STATUS_TRANSACTION_ABORTED;
2154         }
2155
2156         talloc_free(user_dn);
2157         return NT_STATUS_OK;
2158 }
2159
2160
2161 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
2162                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
2163 {
2164         struct ldb_message *msg;
2165         struct ldb_dn *basedn;
2166         char *sidstr;
2167         int ret;
2168
2169         sidstr = dom_sid_string(mem_ctx, sid);
2170         NT_STATUS_HAVE_NO_MEMORY(sidstr);
2171
2172         /* We might have to create a ForeignSecurityPrincipal, even if this user
2173          * is in our own domain */
2174
2175         msg = ldb_msg_new(sidstr);
2176         if (msg == NULL) {
2177                 talloc_free(sidstr);
2178                 return NT_STATUS_NO_MEMORY;
2179         }
2180
2181         ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2182                                 ldb_get_default_basedn(sam_ctx),
2183                                 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2184                                 &basedn);
2185         if (ret != LDB_SUCCESS) {
2186                 DEBUG(0, ("Failed to find DN for "
2187                           "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2188                 talloc_free(sidstr);
2189                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2190         }
2191
2192         /* add core elements to the ldb_message for the alias */
2193         msg->dn = basedn;
2194         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2195                 talloc_free(sidstr);
2196                 return NT_STATUS_NO_MEMORY;
2197         }
2198
2199         samdb_msg_add_string(sam_ctx, msg, msg,
2200                              "objectClass",
2201                              "foreignSecurityPrincipal");
2202
2203         /* create the alias */
2204         ret = ldb_add(sam_ctx, msg);
2205         if (ret != LDB_SUCCESS) {
2206                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2207                          "record %s: %s\n", 
2208                          ldb_dn_get_linearized(msg->dn),
2209                          ldb_errstring(sam_ctx)));
2210                 talloc_free(sidstr);
2211                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2212         }
2213
2214         *ret_dn = talloc_steal(mem_ctx, msg->dn);
2215         talloc_free(sidstr);
2216
2217         return NT_STATUS_OK;
2218 }
2219
2220
2221 /*
2222   Find the DN of a domain, assuming it to be a dotted.dns name
2223 */
2224
2225 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) 
2226 {
2227         unsigned int i;
2228         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2229         const char *binary_encoded;
2230         const char **split_realm;
2231         struct ldb_dn *dn;
2232
2233         if (!tmp_ctx) {
2234                 return NULL;
2235         }
2236
2237         split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2238         if (!split_realm) {
2239                 talloc_free(tmp_ctx);
2240                 return NULL;
2241         }
2242         dn = ldb_dn_new(mem_ctx, ldb, NULL);
2243         for (i=0; split_realm[i]; i++) {
2244                 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2245                 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2246                         DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2247                                   binary_encoded, ldb_dn_get_linearized(dn)));
2248                         talloc_free(tmp_ctx);
2249                         return NULL;
2250                 }
2251         }
2252         if (!ldb_dn_validate(dn)) {
2253                 DEBUG(2, ("Failed to validated DN %s\n",
2254                           ldb_dn_get_linearized(dn)));
2255                 talloc_free(tmp_ctx);
2256                 return NULL;
2257         }
2258         talloc_free(tmp_ctx);
2259         return dn;
2260 }
2261
2262 /*
2263   Find the DN of a domain, be it the netbios or DNS name 
2264 */
2265 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
2266                                   const char *domain_name) 
2267 {
2268         const char * const domain_ref_attrs[] = {
2269                 "ncName", NULL
2270         };
2271         const char * const domain_ref2_attrs[] = {
2272                 NULL
2273         };
2274         struct ldb_result *res_domain_ref;
2275         char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2276         /* find the domain's DN */
2277         int ret_domain = ldb_search(ldb, mem_ctx,
2278                                             &res_domain_ref, 
2279                                             samdb_partitions_dn(ldb, mem_ctx), 
2280                                             LDB_SCOPE_ONELEVEL, 
2281                                             domain_ref_attrs,
2282                                             "(&(nETBIOSName=%s)(objectclass=crossRef))", 
2283                                             escaped_domain);
2284         if (ret_domain != 0) {
2285                 return NULL;
2286         }
2287
2288         if (res_domain_ref->count == 0) {
2289                 ret_domain = ldb_search(ldb, mem_ctx,
2290                                                 &res_domain_ref, 
2291                                                 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2292                                                 LDB_SCOPE_BASE,
2293                                                 domain_ref2_attrs,
2294                                                 "(objectclass=domain)");
2295                 if (ret_domain != 0) {
2296                         return NULL;
2297                 }
2298
2299                 if (res_domain_ref->count == 1) {
2300                         return res_domain_ref->msgs[0]->dn;
2301                 }
2302                 return NULL;
2303         }
2304
2305         if (res_domain_ref->count > 1) {
2306                 DEBUG(0,("Found %d records matching domain [%s]\n", 
2307                          ret_domain, domain_name));
2308                 return NULL;
2309         }
2310
2311         return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2312
2313 }
2314
2315
2316 /*
2317   use a GUID to find a DN
2318  */
2319 int dsdb_find_dn_by_guid(struct ldb_context *ldb, 
2320                          TALLOC_CTX *mem_ctx,
2321                          const struct GUID *guid, struct ldb_dn **dn)
2322 {
2323         int ret;
2324         struct ldb_result *res;
2325         const char *attrs[] = { NULL };
2326         char *guid_str = GUID_string(mem_ctx, guid);
2327
2328         if (!guid_str) {
2329                 return LDB_ERR_OPERATIONS_ERROR;
2330         }
2331
2332         ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2333                           DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2334                           DSDB_SEARCH_SHOW_EXTENDED_DN |
2335                           DSDB_SEARCH_ONE_ONLY,
2336                           "objectGUID=%s", guid_str);
2337         talloc_free(guid_str);
2338         if (ret != LDB_SUCCESS) {
2339                 return ret;
2340         }
2341
2342         *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2343         talloc_free(res);
2344
2345         return LDB_SUCCESS;
2346 }
2347
2348 /*
2349   use a DN to find a GUID with a given attribute name
2350  */
2351 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2352                               struct ldb_dn *dn, const char *attribute,
2353                               struct GUID *guid)
2354 {
2355         int ret;
2356         struct ldb_result *res;
2357         const char *attrs[2];
2358         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2359
2360         attrs[0] = attribute;
2361         attrs[1] = NULL;
2362
2363         ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
2364         if (ret != LDB_SUCCESS) {
2365                 talloc_free(tmp_ctx);
2366                 return ret;
2367         }
2368         if (res->count < 1) {
2369                 talloc_free(tmp_ctx);
2370                 return LDB_ERR_NO_SUCH_OBJECT;
2371         }
2372         *guid = samdb_result_guid(res->msgs[0], attribute);
2373         talloc_free(tmp_ctx);
2374         return LDB_SUCCESS;
2375 }
2376
2377 /*
2378   use a DN to find a GUID
2379  */
2380 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2381                          struct ldb_dn *dn, struct GUID *guid)
2382 {
2383         return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2384 }
2385
2386
2387
2388 /*
2389  adds the given GUID to the given ldb_message. This value is added
2390  for the given attr_name (may be either "objectGUID" or "parentGUID").
2391  */
2392 int dsdb_msg_add_guid(struct ldb_message *msg,
2393                 struct GUID *guid,
2394                 const char *attr_name)
2395 {
2396         int ret;
2397         struct ldb_val v;
2398         NTSTATUS status;
2399         TALLOC_CTX *tmp_ctx =  talloc_init("dsdb_msg_add_guid");
2400
2401         status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2402         if (!NT_STATUS_IS_OK(status)) {
2403                 ret = LDB_ERR_OPERATIONS_ERROR;
2404                 goto done;
2405         }
2406
2407         ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2408         if (ret != LDB_SUCCESS) {
2409                 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2410                                          attr_name));
2411                 goto done;
2412         }
2413
2414         ret = LDB_SUCCESS;
2415
2416 done:
2417         talloc_free(tmp_ctx);
2418         return ret;
2419
2420 }
2421
2422
2423 /*
2424   use a DN to find a SID
2425  */
2426 int dsdb_find_sid_by_dn(struct ldb_context *ldb, 
2427                         struct ldb_dn *dn, struct dom_sid *sid)
2428 {
2429         int ret;
2430         struct ldb_result *res;
2431         const char *attrs[] = { "objectSID", NULL };
2432         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2433         struct dom_sid *s;
2434
2435         ZERO_STRUCTP(sid);
2436
2437         ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
2438         if (ret != LDB_SUCCESS) {
2439                 talloc_free(tmp_ctx);
2440                 return ret;
2441         }
2442         if (res->count < 1) {
2443                 talloc_free(tmp_ctx);
2444                 return LDB_ERR_NO_SUCH_OBJECT;
2445         }
2446         s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSID");
2447         if (s == NULL) {
2448                 talloc_free(tmp_ctx);
2449                 return LDB_ERR_NO_SUCH_OBJECT;
2450         }
2451         *sid = *s;
2452         talloc_free(tmp_ctx);
2453         return LDB_SUCCESS;
2454 }
2455
2456
2457 /*
2458   load a repsFromTo blob list for a given partition GUID
2459   attr must be "repsFrom" or "repsTo"
2460  */
2461 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2462                      const char *attr, struct repsFromToBlob **r, uint32_t *count)
2463 {
2464         const char *attrs[] = { attr, NULL };
2465         struct ldb_result *res = NULL;
2466         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2467         unsigned int i;
2468         struct ldb_message_element *el;
2469
2470         *r = NULL;
2471         *count = 0;
2472
2473         if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2474             res->count < 1) {
2475                 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2476                 talloc_free(tmp_ctx);
2477                 return WERR_DS_DRA_INTERNAL_ERROR;
2478         }
2479
2480         el = ldb_msg_find_element(res->msgs[0], attr);
2481         if (el == NULL) {
2482                 /* it's OK to be empty */
2483                 talloc_free(tmp_ctx);
2484                 return WERR_OK;
2485         }
2486
2487         *count = el->num_values;
2488         *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2489         if (*r == NULL) {
2490                 talloc_free(tmp_ctx);
2491                 return WERR_DS_DRA_INTERNAL_ERROR;
2492         }
2493
2494         for (i=0; i<(*count); i++) {
2495                 enum ndr_err_code ndr_err;
2496                 ndr_err = ndr_pull_struct_blob(&el->values[i], 
2497                                                mem_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2498                                                &(*r)[i], 
2499                                                (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2500                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2501                         talloc_free(tmp_ctx);
2502                         return WERR_DS_DRA_INTERNAL_ERROR;
2503                 }
2504         }
2505
2506         talloc_free(tmp_ctx);
2507         
2508         return WERR_OK;
2509 }
2510
2511 /*
2512   save the repsFromTo blob list for a given partition GUID
2513   attr must be "repsFrom" or "repsTo"
2514  */
2515 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2516                      const char *attr, struct repsFromToBlob *r, uint32_t count)
2517 {
2518         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2519         struct ldb_message *msg;
2520         struct ldb_message_element *el;
2521         unsigned int i;
2522
2523         msg = ldb_msg_new(tmp_ctx);
2524         msg->dn = dn;
2525         if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2526                 goto failed;
2527         }
2528
2529         el->values = talloc_array(msg, struct ldb_val, count);
2530         if (!el->values) {
2531                 goto failed;
2532         }
2533
2534         for (i=0; i<count; i++) {
2535                 struct ldb_val v;
2536                 enum ndr_err_code ndr_err;
2537
2538                 ndr_err = ndr_push_struct_blob(&v, tmp_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2539                                                &r[i], 
2540                                                (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2541                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2542                         goto failed;
2543                 }
2544
2545                 el->num_values++;
2546                 el->values[i] = v;
2547         }
2548
2549         if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2550                 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2551                 goto failed;
2552         }
2553
2554         talloc_free(tmp_ctx);
2555         
2556         return WERR_OK;
2557
2558 failed:
2559         talloc_free(tmp_ctx);
2560         return WERR_DS_DRA_INTERNAL_ERROR;
2561 }
2562
2563
2564 /*
2565   load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2566   object for a partition
2567  */
2568 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2569                                 uint64_t *uSN, uint64_t *urgent_uSN)
2570 {
2571         struct ldb_request *req;
2572         int ret;
2573         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2574         struct dsdb_control_current_partition *p_ctrl;
2575         struct ldb_result *res;
2576
2577         res = talloc_zero(tmp_ctx, struct ldb_result);
2578         if (!res) {
2579                 talloc_free(tmp_ctx);
2580                 return LDB_ERR_OPERATIONS_ERROR;
2581         }
2582
2583         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2584                                    ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2585                                    LDB_SCOPE_BASE,
2586                                    NULL, NULL,
2587                                    NULL,
2588                                    res, ldb_search_default_callback,
2589                                    NULL);
2590         if (ret != LDB_SUCCESS) {
2591                 talloc_free(tmp_ctx);
2592                 return ret;
2593         }
2594
2595         p_ctrl = talloc(req, struct dsdb_control_current_partition);
2596         if (p_ctrl == NULL) {
2597                 talloc_free(res);
2598                 return LDB_ERR_OPERATIONS_ERROR;
2599         }
2600         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2601         p_ctrl->dn = dn;
2602         
2603
2604         ret = ldb_request_add_control(req,
2605                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
2606                                       false, p_ctrl);
2607         if (ret != LDB_SUCCESS) {
2608                 talloc_free(tmp_ctx);
2609                 return ret;
2610         }
2611         
2612         /* Run the new request */
2613         ret = ldb_request(ldb, req);
2614         
2615         if (ret == LDB_SUCCESS) {
2616                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2617         }
2618
2619         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2620                 /* it hasn't been created yet, which means
2621                    an implicit value of zero */
2622                 *uSN = 0;
2623                 talloc_free(tmp_ctx);
2624                 return LDB_SUCCESS;
2625         }
2626
2627         if (ret != LDB_SUCCESS) {
2628                 talloc_free(tmp_ctx);
2629                 return ret;
2630         }
2631
2632         if (res->count < 1) {
2633                 *uSN = 0;
2634                 if (urgent_uSN) {
2635                         *urgent_uSN = 0;
2636                 }
2637         } else {
2638                 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2639                 if (urgent_uSN) {
2640                         *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2641                 }
2642         }
2643
2644         talloc_free(tmp_ctx);
2645
2646         return LDB_SUCCESS;     
2647 }
2648
2649 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2650                                                    const struct drsuapi_DsReplicaCursor2 *c2)
2651 {
2652         return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2653 }
2654
2655 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2656                                     const struct drsuapi_DsReplicaCursor *c2)
2657 {
2658         return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2659 }
2660
2661
2662 /*
2663   see if a computer identified by its invocationId is a RODC
2664 */
2665 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2666 {
2667         /* 1) find the DN for this servers NTDSDSA object
2668            2) search for the msDS-isRODC attribute
2669            3) if not present then not a RODC
2670            4) if present and TRUE then is a RODC
2671         */
2672         struct ldb_dn *config_dn;
2673         const char *attrs[] = { "msDS-isRODC", NULL };
2674         int ret;
2675         struct ldb_result *res;
2676         TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2677
2678         config_dn = ldb_get_config_basedn(sam_ctx);
2679         if (!config_dn) {
2680                 talloc_free(tmp_ctx);
2681                 return LDB_ERR_OPERATIONS_ERROR;
2682         }
2683
2684         ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2685                           DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2686
2687         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2688                 *is_rodc = false;
2689                 talloc_free(tmp_ctx);
2690                 return LDB_SUCCESS;
2691         }
2692
2693         if (ret != LDB_SUCCESS) {
2694                 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2695                          GUID_string(tmp_ctx, objectGUID)));
2696                 *is_rodc = false;
2697                 talloc_free(tmp_ctx);
2698                 return ret;
2699         }
2700
2701         ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2702         *is_rodc = (ret == 1);
2703
2704         talloc_free(tmp_ctx);
2705         return LDB_SUCCESS;
2706 }
2707
2708
2709 /*
2710   see if we are a RODC
2711 */
2712 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2713 {
2714         const struct GUID *objectGUID;
2715         int ret;
2716         bool *cached;
2717
2718         /* see if we have a cached copy */
2719         cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2720         if (cached) {
2721                 *am_rodc = *cached;
2722                 return LDB_SUCCESS;
2723         }
2724
2725         objectGUID = samdb_ntds_objectGUID(sam_ctx);
2726         if (!objectGUID) {
2727                 return LDB_ERR_OPERATIONS_ERROR;
2728         }
2729
2730         ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2731         if (ret != LDB_SUCCESS) {
2732                 return ret;
2733         }
2734
2735         cached = talloc(sam_ctx, bool);
2736         if (cached == NULL) {
2737                 return LDB_ERR_OPERATIONS_ERROR;
2738         }
2739         *cached = *am_rodc;
2740
2741         ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2742         if (ret != LDB_SUCCESS) {
2743                 talloc_free(cached);
2744                 return LDB_ERR_OPERATIONS_ERROR;
2745         }
2746
2747         return LDB_SUCCESS;
2748 }
2749
2750
2751
2752 /*
2753   return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1 
2754
2755   flags are DS_NTDS_OPTION_*
2756 */
2757 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2758 {
2759         TALLOC_CTX *tmp_ctx;
2760         const char *attrs[] = { "options", NULL };
2761         int ret;
2762         struct ldb_result *res;
2763
2764         tmp_ctx = talloc_new(ldb);
2765         if (tmp_ctx == NULL) {
2766                 goto failed;
2767         }
2768
2769         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2770         if (ret) {
2771                 goto failed;
2772         }
2773
2774         if (res->count != 1) {
2775                 goto failed;
2776         }
2777
2778         *options = samdb_result_uint(res->msgs[0], "options", 0);
2779
2780         talloc_free(tmp_ctx);
2781
2782         return LDB_SUCCESS;
2783
2784 failed:
2785         DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
2786         talloc_free(tmp_ctx);
2787         return LDB_ERR_NO_SUCH_OBJECT;
2788 }
2789
2790 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
2791 {
2792         const char *attrs[] = { "objectCategory", NULL };
2793         int ret;
2794         struct ldb_result *res;
2795
2796         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2797         if (ret) {
2798                 goto failed;
2799         }
2800
2801         if (res->count != 1) {
2802                 goto failed;
2803         }
2804
2805         return samdb_result_string(res->msgs[0], "objectCategory", NULL);
2806
2807 failed:
2808         DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
2809         return NULL;
2810 }
2811
2812 /*
2813  * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
2814  * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
2815  */
2816 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
2817 {
2818         char **tokens, *ret;
2819         size_t i;
2820
2821         tokens = str_list_make(mem_ctx, cn, " -_");
2822         if (tokens == NULL)
2823                 return NULL;
2824
2825         /* "tolower()" and "toupper()" should also work properly on 0x00 */
2826         tokens[0][0] = tolower(tokens[0][0]);
2827         for (i = 1; i < str_list_length((const char **)tokens); i++)
2828                 tokens[i][0] = toupper(tokens[i][0]);
2829
2830         ret = talloc_strdup(mem_ctx, tokens[0]);
2831         for (i = 1; i < str_list_length((const char **)tokens); i++)
2832                 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
2833
2834         talloc_free(tokens);
2835
2836         return ret;
2837 }
2838
2839 /*
2840   return domain functional level
2841   returns DS_DOMAIN_FUNCTION_*
2842  */
2843 int dsdb_functional_level(struct ldb_context *ldb)
2844 {
2845         int *domainFunctionality =
2846                 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
2847         if (!domainFunctionality) {
2848                 DEBUG(0,(__location__ ": WARNING: domainFunctionality not setup\n"));
2849                 return DS_DOMAIN_FUNCTION_2000;
2850         }
2851         return *domainFunctionality;
2852 }
2853
2854 /*
2855   set a GUID in an extended DN structure
2856  */
2857 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
2858 {
2859         struct ldb_val v;
2860         NTSTATUS status;
2861         int ret;
2862
2863         status = GUID_to_ndr_blob(guid, dn, &v);
2864         if (!NT_STATUS_IS_OK(status)) {
2865                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
2866         }
2867
2868         ret = ldb_dn_set_extended_component(dn, component_name, &v);
2869         data_blob_free(&v);
2870         return ret;
2871 }
2872
2873 /*
2874   return a GUID from a extended DN structure
2875  */
2876 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
2877 {
2878         const struct ldb_val *v;
2879
2880         v = ldb_dn_get_extended_component(dn, component_name);
2881         if (v == NULL) {
2882                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2883         }
2884
2885         return GUID_from_ndr_blob(v, guid);
2886 }
2887
2888 /*
2889   return a uint64_t from a extended DN structure
2890  */
2891 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
2892 {
2893         const struct ldb_val *v;
2894         char *s;
2895
2896         v = ldb_dn_get_extended_component(dn, component_name);
2897         if (v == NULL) {
2898                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2899         }
2900         s = talloc_strndup(dn, (const char *)v->data, v->length);
2901         NT_STATUS_HAVE_NO_MEMORY(s);
2902
2903         *val = strtoull(s, NULL, 0);
2904
2905         talloc_free(s);
2906         return NT_STATUS_OK;
2907 }
2908
2909 /*
2910   return a NTTIME from a extended DN structure
2911  */
2912 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
2913 {
2914         return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
2915 }
2916
2917 /*
2918   return a uint32_t from a extended DN structure
2919  */
2920 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
2921 {
2922         const struct ldb_val *v;
2923         char *s;
2924
2925         v = ldb_dn_get_extended_component(dn, component_name);
2926         if (v == NULL) {
2927                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2928         }
2929
2930         s = talloc_strndup(dn, (const char *)v->data, v->length);
2931         NT_STATUS_HAVE_NO_MEMORY(s);
2932
2933         *val = strtoul(s, NULL, 0);
2934
2935         talloc_free(s);
2936         return NT_STATUS_OK;
2937 }
2938
2939 /*
2940   return a dom_sid from a extended DN structure
2941  */
2942 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
2943 {
2944         const struct ldb_val *sid_blob;
2945         struct TALLOC_CTX *tmp_ctx;
2946         enum ndr_err_code ndr_err;
2947
2948         sid_blob = ldb_dn_get_extended_component(dn, "SID");
2949         if (!sid_blob) {
2950                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2951         }
2952
2953         tmp_ctx = talloc_new(NULL);
2954
2955         ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, NULL, sid,
2956                                            (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
2957         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2958                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2959                 talloc_free(tmp_ctx);
2960                 return status;
2961         }
2962
2963         talloc_free(tmp_ctx);
2964         return NT_STATUS_OK;
2965 }
2966
2967
2968 /*
2969   return RMD_FLAGS directly from a ldb_dn
2970   returns 0 if not found
2971  */
2972 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
2973 {
2974         const struct ldb_val *v;
2975         char buf[32];
2976         v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
2977         if (!v || v->length > sizeof(buf)-1) return 0;
2978         strncpy(buf, (const char *)v->data, v->length);
2979         buf[v->length] = 0;
2980         return strtoul(buf, NULL, 10);
2981 }
2982
2983 /*
2984   return RMD_FLAGS directly from a ldb_val for a DN
2985   returns 0 if RMD_FLAGS is not found
2986  */
2987 uint32_t dsdb_dn_val_rmd_flags(struct ldb_val *val)
2988 {
2989         const char *p;
2990         uint32_t flags;
2991         char *end;
2992
2993         if (val->length < 13) {
2994                 return 0;
2995         }
2996         p = memmem(val->data, val->length-2, "<RMD_FLAGS=", 11);
2997         if (!p) {
2998                 return 0;
2999         }
3000         flags = strtoul(p+11, &end, 10);
3001         if (!end || *end != '>') {
3002                 /* it must end in a > */
3003                 return 0;
3004         }
3005         return flags;
3006 }
3007
3008 /*
3009   return true if a ldb_val containing a DN in storage form is deleted
3010  */
3011 bool dsdb_dn_is_deleted_val(struct ldb_val *val)
3012 {
3013         return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3014 }
3015
3016 /*
3017   return true if a ldb_val containing a DN in storage form is
3018   in the upgraded w2k3 linked attribute format
3019  */
3020 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3021 {
3022         return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3023 }
3024
3025 /*
3026   return a DN for a wellknown GUID
3027  */
3028 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3029                       struct ldb_dn *nc_root, const char *wk_guid,
3030                       struct ldb_dn **wkguid_dn)
3031 {
3032         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3033         const char *attrs[] = { NULL };
3034         int ret;
3035         struct ldb_dn *dn;
3036         struct ldb_result *res;
3037
3038         /* construct the magic WKGUID DN */
3039         dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3040                             wk_guid, ldb_dn_get_linearized(nc_root));
3041         if (!wkguid_dn) {
3042                 talloc_free(tmp_ctx);
3043                 return LDB_ERR_OPERATIONS_ERROR;
3044         }
3045
3046         ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
3047         if (ret != LDB_SUCCESS) {
3048                 talloc_free(tmp_ctx);
3049                 return ret;
3050         }
3051
3052         (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3053         talloc_free(tmp_ctx);
3054         return LDB_SUCCESS;
3055 }
3056
3057
3058 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3059 {
3060         return ldb_dn_compare(*dn1, *dn2);
3061 }
3062
3063 /*
3064   find a NC root given a DN within the NC
3065  */
3066 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3067                       struct ldb_dn **nc_root)
3068 {
3069         const char *root_attrs[] = { "namingContexts", NULL };
3070         TALLOC_CTX *tmp_ctx;
3071         int ret;
3072         struct ldb_message_element *el;
3073         struct ldb_result *root_res;
3074         int i;
3075         struct ldb_dn **nc_dns;
3076
3077         tmp_ctx = talloc_new(samdb);
3078         if (tmp_ctx == NULL) {
3079                 return LDB_ERR_OPERATIONS_ERROR;
3080         }
3081
3082         ret = ldb_search(samdb, tmp_ctx, &root_res,
3083                          ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3084         if (ret) {
3085                 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3086                 talloc_free(tmp_ctx);
3087                 return ret;
3088        }
3089
3090        el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3091        if (!el) {
3092                DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3093                         ldb_errstring(samdb)));
3094                talloc_free(tmp_ctx);
3095                return LDB_ERR_NO_SUCH_ATTRIBUTE;
3096        }
3097
3098        nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3099        if (!nc_dns) {
3100                talloc_free(tmp_ctx);
3101                return LDB_ERR_OPERATIONS_ERROR;
3102        }
3103
3104        for (i=0; i<el->num_values; i++) {
3105                nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3106                if (nc_dns[i] == NULL) {
3107                        talloc_free(tmp_ctx);
3108                        return LDB_ERR_OPERATIONS_ERROR;
3109                }
3110        }
3111
3112        TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3113
3114        for (i=0; i<el->num_values; i++) {
3115                if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3116                        (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3117                        talloc_free(tmp_ctx);
3118                        return LDB_SUCCESS;
3119                }
3120        }
3121
3122        talloc_free(tmp_ctx);
3123        return LDB_ERR_NO_SUCH_OBJECT;
3124 }
3125
3126
3127 /*
3128   find the deleted objects DN for any object, by looking for the NC
3129   root, then looking up the wellknown GUID
3130  */
3131 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3132                                 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3133                                 struct ldb_dn **do_dn)
3134 {
3135         struct ldb_dn *nc_root;
3136         int ret;
3137
3138         ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3139         if (ret != LDB_SUCCESS) {
3140                 return ret;
3141         }
3142
3143         ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3144         talloc_free(nc_root);
3145         return ret;
3146 }
3147
3148 /*
3149   return the tombstoneLifetime, in days
3150  */
3151 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3152 {
3153         struct ldb_dn *dn;
3154         dn = ldb_get_config_basedn(ldb);
3155         if (!dn) {
3156                 return LDB_ERR_NO_SUCH_OBJECT;
3157         }
3158         dn = ldb_dn_copy(ldb, dn);
3159         if (!dn) {
3160                 return LDB_ERR_OPERATIONS_ERROR;
3161         }
3162         /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3163          be a wellknown GUID for this */
3164         if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3165                 talloc_free(dn);
3166                 return LDB_ERR_OPERATIONS_ERROR;
3167         }
3168
3169         *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3170         talloc_free(dn);
3171         return LDB_SUCCESS;
3172 }
3173
3174 /*
3175   compare a ldb_val to a string case insensitively
3176  */
3177 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3178 {
3179         size_t len = strlen(s);
3180         int ret;
3181         if (len > v->length) return 1;
3182         ret = strncasecmp(s, (const char *)v->data, v->length);
3183         if (ret != 0) return ret;
3184         if (v->length > len && v->data[len] != 0) {
3185                 return -1;
3186         }
3187         return 0;
3188 }
3189
3190
3191 /*
3192   load the UDV for a partition in v2 format
3193   The list is returned sorted, and with our local cursor added
3194  */
3195 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3196                      struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3197 {
3198         static const char *attrs[] = { "replUpToDateVector", NULL };
3199         struct ldb_result *r;
3200         const struct ldb_val *ouv_value;
3201         unsigned int i;
3202         int ret;
3203         uint64_t highest_usn;
3204         const struct GUID *our_invocation_id;
3205         struct timeval now = timeval_current();
3206
3207         ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3208         if (ret != LDB_SUCCESS) {
3209                 return ret;
3210         }
3211
3212         ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3213         if (ouv_value) {
3214                 enum ndr_err_code ndr_err;
3215                 struct replUpToDateVectorBlob ouv;
3216
3217                 ndr_err = ndr_pull_struct_blob(ouv_value, r,
3218                                                lp_iconv_convenience(ldb_get_opaque(samdb, "loadparm")), &ouv,
3219                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3220                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3221                         talloc_free(r);
3222                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3223                 }
3224                 if (ouv.version != 2) {
3225                         /* we always store as version 2, and
3226                          * replUpToDateVector is not replicated
3227                          */
3228                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3229                 }
3230
3231                 *count = ouv.ctr.ctr2.count;
3232                 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3233         } else {
3234                 *count = 0;
3235                 *cursors = NULL;
3236         }
3237
3238         talloc_free(r);
3239
3240         our_invocation_id = samdb_ntds_invocation_id(samdb);
3241         if (!our_invocation_id) {
3242                 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3243                 talloc_free(*cursors);
3244                 return LDB_ERR_OPERATIONS_ERROR;
3245         }
3246
3247         ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3248         if (ret != LDB_SUCCESS) {
3249                 /* nothing to add - this can happen after a vampire */
3250                 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3251                 return LDB_SUCCESS;
3252         }
3253
3254         for (i=0; i<*count; i++) {
3255                 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3256                         (*cursors)[i].highest_usn = highest_usn;
3257                         (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3258                         TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3259                         return LDB_SUCCESS;
3260                 }
3261         }
3262
3263         (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3264         if (! *cursors) {
3265                 return LDB_ERR_OPERATIONS_ERROR;
3266         }
3267
3268         (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3269         (*cursors)[*count].highest_usn = highest_usn;
3270         (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3271         (*count)++;
3272
3273         TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3274
3275         return LDB_SUCCESS;
3276 }
3277
3278 /*
3279   load the UDV for a partition in version 1 format
3280   The list is returned sorted, and with our local cursor added
3281  */
3282 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3283                      struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3284 {
3285         struct drsuapi_DsReplicaCursor2 *v2;
3286         unsigned int i;
3287         int ret;
3288
3289         ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3290         if (ret != LDB_SUCCESS) {
3291                 return ret;
3292         }
3293
3294         if (*count == 0) {
3295                 talloc_free(v2);
3296                 *cursors = NULL;
3297                 return LDB_SUCCESS;
3298         }
3299
3300         *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3301         if (*cursors == NULL) {
3302                 talloc_free(v2);
3303                 return LDB_ERR_OPERATIONS_ERROR;
3304         }
3305
3306         for (i=0; i<*count; i++) {
3307                 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3308                 (*cursors)[i].highest_usn = v2[i].highest_usn;
3309         }
3310         talloc_free(v2);
3311         return LDB_SUCCESS;
3312 }
3313
3314 /*
3315   add a set of controls to a ldb_request structure based on a set of
3316   flags. See util.h for a list of available flags
3317  */
3318 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3319 {
3320         int ret;
3321         if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3322                 struct ldb_search_options_control *options;
3323                 /* Using the phantom root control allows us to search all partitions */
3324                 options = talloc(req, struct ldb_search_options_control);
3325                 if (options == NULL) {
3326                         return LDB_ERR_OPERATIONS_ERROR;
3327                 }
3328                 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3329
3330                 ret = ldb_request_add_control(req,
3331                                               LDB_CONTROL_SEARCH_OPTIONS_OID,
3332                                               true, options);
3333                 if (ret != LDB_SUCCESS) {
3334                         return ret;
3335                 }
3336         }
3337
3338         if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3339                 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3340                 if (ret != LDB_SUCCESS) {
3341                         return ret;
3342                 }
3343         }
3344
3345         if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3346                 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3347                 if (ret != LDB_SUCCESS) {
3348                         return ret;
3349                 }
3350         }
3351
3352         if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3353                 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3354                 if (!extended_ctrl) {
3355                         return LDB_ERR_OPERATIONS_ERROR;
3356                 }
3357                 extended_ctrl->type = 1;
3358
3359                 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3360                 if (ret != LDB_SUCCESS) {
3361                         return ret;
3362                 }
3363         }
3364
3365         if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3366                 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3367                 if (ret != LDB_SUCCESS) {
3368                         return ret;
3369                 }
3370         }
3371
3372         if (dsdb_flags & DSDB_MODIFY_RELAX) {
3373                 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3374                 if (ret != LDB_SUCCESS) {
3375                         return ret;
3376                 }
3377         }
3378
3379         if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3380                 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3381                 if (ret != LDB_SUCCESS) {
3382                         return ret;
3383                 }
3384         }
3385
3386         if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3387                 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3388                 if (ret != LDB_SUCCESS) {
3389                         return ret;
3390                 }
3391         }
3392
3393         return LDB_SUCCESS;
3394 }
3395
3396 /*
3397   a modify with a set of controls
3398 */
3399 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3400                 uint32_t dsdb_flags)
3401 {
3402         struct ldb_request *req;
3403         int ret;
3404
3405         ret = ldb_build_mod_req(&req, ldb, ldb,
3406                                 message,
3407                                 NULL,
3408                                 NULL,
3409                                 ldb_op_default_callback,
3410                                 NULL);
3411
3412         if (ret != LDB_SUCCESS) return ret;
3413
3414         ret = dsdb_request_add_controls(req, dsdb_flags);
3415         if (ret != LDB_SUCCESS) {
3416                 talloc_free(req);
3417                 return ret;
3418         }
3419
3420         ret = dsdb_autotransaction_request(ldb, req);
3421
3422         talloc_free(req);
3423         return ret;
3424 }
3425
3426 /*
3427   like dsdb_modify() but set all the element flags to
3428   LDB_FLAG_MOD_REPLACE
3429  */
3430 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3431 {
3432         unsigned int i;
3433
3434         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3435         for (i=0;i<msg->num_elements;i++) {
3436                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3437         }
3438
3439         return dsdb_modify(ldb, msg, dsdb_flags);
3440 }
3441
3442
3443 /*
3444   search for attrs on one DN, allowing for dsdb_flags controls
3445  */
3446 int dsdb_search_dn(struct ldb_context *ldb,
3447                    TALLOC_CTX *mem_ctx,
3448                    struct ldb_result **_res,
3449                    struct ldb_dn *basedn,
3450                    const char * const *attrs,
3451                    uint32_t dsdb_flags)
3452 {
3453         int ret;
3454         struct ldb_request *req;
3455         struct ldb_result *res;
3456
3457         res = talloc_zero(mem_ctx, struct ldb_result);
3458         if (!res) {
3459                 return LDB_ERR_OPERATIONS_ERROR;
3460         }
3461
3462         ret = ldb_build_search_req(&req, ldb, res,
3463                                    basedn,
3464                                    LDB_SCOPE_BASE,
3465                                    NULL,
3466                                    attrs,
3467                                    NULL,
3468                                    res,
3469                                    ldb_search_default_callback,
3470                                    NULL);
3471         if (ret != LDB_SUCCESS) {
3472                 talloc_free(res);
3473                 return ret;
3474         }
3475
3476         ret = dsdb_request_add_controls(req, dsdb_flags);
3477         if (ret != LDB_SUCCESS) {
3478                 talloc_free(res);
3479                 return ret;
3480         }
3481
3482         ret = ldb_request(ldb, req);
3483         if (ret == LDB_SUCCESS) {
3484                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3485         }
3486
3487         talloc_free(req);
3488         if (ret != LDB_SUCCESS) {
3489                 talloc_free(res);
3490                 return ret;
3491         }
3492
3493         *_res = res;
3494         return LDB_SUCCESS;
3495 }
3496
3497 /*
3498   general search with dsdb_flags for controls
3499  */
3500 int dsdb_search(struct ldb_context *ldb,
3501                 TALLOC_CTX *mem_ctx,
3502                 struct ldb_result **_res,
3503                 struct ldb_dn *basedn,
3504                 enum ldb_scope scope,
3505                 const char * const *attrs,
3506                 uint32_t dsdb_flags,
3507                 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3508 {
3509         int ret;
3510         struct ldb_request *req;
3511         struct ldb_result *res;
3512         va_list ap;
3513         char *expression = NULL;
3514         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3515
3516         res = talloc_zero(tmp_ctx, struct ldb_result);
3517         if (!res) {
3518                 talloc_free(tmp_ctx);
3519                 return LDB_ERR_OPERATIONS_ERROR;
3520         }
3521
3522         if (exp_fmt) {
3523                 va_start(ap, exp_fmt);
3524                 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3525                 va_end(ap);
3526
3527                 if (!expression) {
3528                         talloc_free(tmp_ctx);
3529                         return LDB_ERR_OPERATIONS_ERROR;
3530                 }
3531         }
3532
3533         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3534                                    basedn,
3535                                    scope,
3536                                    expression,
3537                                    attrs,
3538                                    NULL,
3539                                    res,
3540                                    ldb_search_default_callback,
3541                                    NULL);
3542         if (ret != LDB_SUCCESS) {
3543                 talloc_free(tmp_ctx);
3544                 return ret;
3545         }
3546
3547         ret = dsdb_request_add_controls(req, dsdb_flags);
3548         if (ret != LDB_SUCCESS) {
3549                 talloc_free(tmp_ctx);
3550                 return ret;
3551         }
3552
3553         ret = ldb_request(ldb, req);
3554         if (ret == LDB_SUCCESS) {
3555                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3556         }
3557
3558         if (ret != LDB_SUCCESS) {
3559                 talloc_free(tmp_ctx);
3560                 return ret;
3561         }
3562
3563         if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3564                 if (res->count == 0) {
3565                         talloc_free(tmp_ctx);
3566                         return LDB_ERR_NO_SUCH_OBJECT;
3567                 }
3568                 if (res->count != 1) {
3569                         talloc_free(tmp_ctx);
3570                         return LDB_ERR_CONSTRAINT_VIOLATION;
3571                 }
3572         }
3573
3574         *_res = talloc_steal(mem_ctx, res);
3575         talloc_free(tmp_ctx);
3576
3577         return LDB_SUCCESS;
3578 }
3579
3580
3581 /*
3582   general search with dsdb_flags for controls
3583   returns exactly 1 record or an error
3584  */
3585 int dsdb_search_one(struct ldb_context *ldb,
3586                     TALLOC_CTX *mem_ctx,
3587                     struct ldb_message **msg,
3588                     struct ldb_dn *basedn,
3589                     enum ldb_scope scope,
3590                     const char * const *attrs,
3591                     uint32_t dsdb_flags,
3592                     const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3593 {
3594         int ret;
3595         struct ldb_result *res;
3596         va_list ap;
3597         char *expression = NULL;
3598         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3599
3600         dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3601
3602         res = talloc_zero(tmp_ctx, struct ldb_result);
3603         if (!res) {
3604                 talloc_free(tmp_ctx);
3605                 return LDB_ERR_OPERATIONS_ERROR;
3606         }
3607
3608         if (exp_fmt) {
3609                 va_start(ap, exp_fmt);
3610                 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3611                 va_end(ap);
3612
3613                 if (!expression) {
3614                         talloc_free(tmp_ctx);
3615                         return LDB_ERR_OPERATIONS_ERROR;
3616                 }
3617         }
3618
3619         ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3620                           dsdb_flags, "%s", expression);
3621         if (ret != LDB_SUCCESS) {
3622                 talloc_free(tmp_ctx);
3623                 return ret;
3624         }
3625
3626         *msg = talloc_steal(mem_ctx, res->msgs[0]);
3627         talloc_free(tmp_ctx);
3628
3629         return LDB_SUCCESS;
3630 }
3631
3632 /* returns back the forest DNS name */
3633 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3634 {
3635         const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3636                                                           ldb_get_root_basedn(ldb));
3637         char *p;
3638
3639         if (forest_name == NULL) {
3640                 return NULL;
3641         }
3642
3643         p = strchr(forest_name, '/');
3644         if (p) {
3645                 *p = '\0';
3646         }
3647
3648         return forest_name;
3649 }
3650
3651 /*
3652    validate that an DSA GUID belongs to the specified user sid.
3653    The user SID must be a domain controller account (either RODC or
3654    RWDC)
3655  */
3656 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3657                            const struct GUID *dsa_guid,
3658                            const struct dom_sid *sid)
3659 {
3660         /* strategy:
3661             - find DN of record with the DSA GUID in the
3662               configuration partition (objectGUID)
3663             - remove "NTDS Settings" component from DN
3664             - do a base search on that DN for serverReference with
3665               extended-dn enabled
3666             - extract objectSID from resulting serverReference
3667               attribute
3668             - check this sid matches the sid argument
3669         */
3670         struct ldb_dn *config_dn;
3671         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3672         struct ldb_message *msg;
3673         const char *attrs1[] = { NULL };
3674         const char *attrs2[] = { "serverReference", NULL };
3675         int ret;
3676         struct ldb_dn *dn, *account_dn;
3677         struct dom_sid sid2;
3678         NTSTATUS status;
3679
3680         config_dn = ldb_get_config_basedn(ldb);
3681
3682         ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
3683                               attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
3684         if (ret != LDB_SUCCESS) {
3685                 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
3686                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3687                 talloc_free(tmp_ctx);
3688                 return LDB_ERR_OPERATIONS_ERROR;
3689         }
3690         dn = msg->dn;
3691
3692         if (!ldb_dn_remove_child_components(dn, 1)) {
3693                 talloc_free(tmp_ctx);
3694                 return LDB_ERR_OPERATIONS_ERROR;
3695         }
3696
3697         ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
3698                               attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
3699                               "(objectClass=server)");
3700         if (ret != LDB_SUCCESS) {
3701                 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
3702                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3703                 talloc_free(tmp_ctx);
3704                 return LDB_ERR_OPERATIONS_ERROR;
3705         }
3706
3707         account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
3708         if (account_dn == NULL) {
3709                 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
3710                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3711                 talloc_free(tmp_ctx);
3712                 return LDB_ERR_OPERATIONS_ERROR;
3713         }
3714
3715         status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
3716         if (!NT_STATUS_IS_OK(status)) {
3717                 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
3718                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3719                 talloc_free(tmp_ctx);
3720                 return LDB_ERR_OPERATIONS_ERROR;
3721         }
3722
3723         if (!dom_sid_equal(sid, &sid2)) {
3724                 /* someone is trying to spoof another account */
3725                 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
3726                          GUID_string(tmp_ctx, dsa_guid),
3727                          dom_sid_string(tmp_ctx, sid),
3728                          dom_sid_string(tmp_ctx, &sid2)));
3729                 talloc_free(tmp_ctx);
3730                 return LDB_ERR_OPERATIONS_ERROR;
3731         }
3732
3733         talloc_free(tmp_ctx);
3734         return LDB_SUCCESS;
3735 }
3736
3737 const char *rodc_fas_list[] = {"ms-PKI-DPAPIMasterKeys",
3738                                "ms-PKI-AccountCredentials",
3739                                "ms-PKI-RoamingTimeStamp",
3740                                "ms-FVE-KeyPackage",
3741                                "ms-FVE-RecoveryGuid",
3742                                "ms-FVE-RecoveryInformation",
3743                                "ms-FVE-RecoveryPassword",
3744                                "ms-FVE-VolumeGuid",
3745                                "ms-TPM-OwnerInformation",
3746                                NULL};
3747 /*
3748   check if the attribute belongs to the RODC filtered attribute set
3749 */
3750 bool dsdb_attr_in_rodc_fas(uint32_t replica_flags, const struct dsdb_attribute *sa)
3751 {
3752         int rodc_filtered_flags = SEARCH_FLAG_RODC_ATTRIBUTE | SEARCH_FLAG_CONFIDENTIAL;
3753         bool drs_write_replica = ((replica_flags & DRSUAPI_DRS_WRIT_REP) == 0);
3754
3755         if (drs_write_replica && (sa->searchFlags & rodc_filtered_flags)) {
3756                 return true;
3757         }
3758         if (drs_write_replica && is_attr_in_list(rodc_fas_list, sa->cn)) {
3759                 return true;
3760         }
3761         return false;
3762 }