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