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