s4:dsdb/common/util - Indentation fixes
[ira/wip.git] / source4 / dsdb / common / util.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba utility functions
4
5    Copyright (C) Andrew Tridgell 2004
6    Copyright (C) Volker Lendecke 2004
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "events/events.h"
26 #include "ldb.h"
27 #include "ldb_errors.h"
28 #include "../lib/util/util_ldb.h"
29 #include "../lib/crypto/crypto.h"
30 #include "dsdb/samdb/samdb.h"
31 #include "libcli/security/security.h"
32 #include "librpc/gen_ndr/ndr_security.h"
33 #include "librpc/gen_ndr/ndr_misc.h"
34 #include "../libds/common/flags.h"
35 #include "dsdb/common/proto.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "param/param.h"
38 #include "libcli/auth/libcli_auth.h"
39
40 /*
41   search the sam for the specified attributes in a specific domain, filter on
42   objectSid being in domain_sid.
43 */
44 int samdb_search_domain(struct ldb_context *sam_ldb,
45                         TALLOC_CTX *mem_ctx, 
46                         struct ldb_dn *basedn,
47                         struct ldb_message ***res,
48                         const char * const *attrs,
49                         const struct dom_sid *domain_sid,
50                         const char *format, ...)  _PRINTF_ATTRIBUTE(7,8)
51 {
52         va_list ap;
53         int i, count;
54
55         va_start(ap, format);
56         count = gendb_search_v(sam_ldb, mem_ctx, basedn,
57                                res, attrs, format, ap);
58         va_end(ap);
59
60         i=0;
61
62         while (i<count) {
63                 struct dom_sid *entry_sid;
64
65                 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
66
67                 if ((entry_sid == NULL) ||
68                     (!dom_sid_in_domain(domain_sid, entry_sid))) {
69                         /* Delete that entry from the result set */
70                         (*res)[i] = (*res)[count-1];
71                         count -= 1;
72                         talloc_free(entry_sid);
73                         continue;
74                 }
75                 talloc_free(entry_sid);
76                 i += 1;
77         }
78
79         return count;
80 }
81
82 /*
83   search the sam for a single string attribute in exactly 1 record
84 */
85 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
86                                   TALLOC_CTX *mem_ctx,
87                                   struct ldb_dn *basedn,
88                                   const char *attr_name,
89                                   const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
90 {
91         int count;
92         const char *attrs[2] = { NULL, NULL };
93         struct ldb_message **res = NULL;
94
95         attrs[0] = attr_name;
96
97         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
98         if (count > 1) {                
99                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
100                          attr_name, format, count));
101         }
102         if (count != 1) {
103                 talloc_free(res);
104                 return NULL;
105         }
106
107         return samdb_result_string(res[0], attr_name, NULL);
108 }
109
110 /*
111   search the sam for a single string attribute in exactly 1 record
112 */
113 const char *samdb_search_string(struct ldb_context *sam_ldb,
114                                 TALLOC_CTX *mem_ctx,
115                                 struct ldb_dn *basedn,
116                                 const char *attr_name,
117                                 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
118 {
119         va_list ap;
120         const char *str;
121
122         va_start(ap, format);
123         str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
124         va_end(ap);
125
126         return str;
127 }
128
129 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
130                                TALLOC_CTX *mem_ctx,
131                                struct ldb_dn *basedn,
132                                const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
133 {
134         va_list ap;
135         struct ldb_dn *ret;
136         struct ldb_message **res = NULL;
137         int count;
138
139         va_start(ap, format);
140         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
141         va_end(ap);
142
143         if (count != 1) return NULL;
144
145         ret = talloc_steal(mem_ctx, res[0]->dn);
146         talloc_free(res);
147
148         return ret;
149 }
150
151 /*
152   search the sam for a dom_sid attribute in exactly 1 record
153 */
154 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
155                                      TALLOC_CTX *mem_ctx,
156                                      struct ldb_dn *basedn,
157                                      const char *attr_name,
158                                      const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
159 {
160         va_list ap;
161         int count;
162         struct ldb_message **res;
163         const char *attrs[2] = { NULL, NULL };
164         struct dom_sid *sid;
165
166         attrs[0] = attr_name;
167
168         va_start(ap, format);
169         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
170         va_end(ap);
171         if (count > 1) {                
172                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
173                          attr_name, format, count));
174         }
175         if (count != 1) {
176                 talloc_free(res);
177                 return NULL;
178         }
179         sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
180         talloc_free(res);
181         return sid;     
182 }
183
184 /*
185   return the count of the number of records in the sam matching the query
186 */
187 int samdb_search_count(struct ldb_context *sam_ldb,
188                        TALLOC_CTX *mem_ctx,
189                        struct ldb_dn *basedn,
190                        const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
191 {
192         va_list ap;
193         struct ldb_message **res;
194         const char * const attrs[] = { NULL };
195         int ret;
196
197         va_start(ap, format);
198         ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
199         va_end(ap);
200
201         return ret;
202 }
203
204
205 /*
206   search the sam for a single integer attribute in exactly 1 record
207 */
208 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
209                          TALLOC_CTX *mem_ctx,
210                          uint_t default_value,
211                          struct ldb_dn *basedn,
212                          const char *attr_name,
213                          const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
214 {
215         va_list ap;
216         int count;
217         struct ldb_message **res;
218         const char *attrs[2] = { NULL, NULL };
219
220         attrs[0] = attr_name;
221
222         va_start(ap, format);
223         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
224         va_end(ap);
225
226         if (count != 1) {
227                 return default_value;
228         }
229
230         return samdb_result_uint(res[0], attr_name, default_value);
231 }
232
233 /*
234   search the sam for a single signed 64 bit integer attribute in exactly 1 record
235 */
236 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
237                            TALLOC_CTX *mem_ctx,
238                            int64_t default_value,
239                            struct ldb_dn *basedn,
240                            const char *attr_name,
241                            const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
242 {
243         va_list ap;
244         int count;
245         struct ldb_message **res;
246         const char *attrs[2] = { NULL, NULL };
247
248         attrs[0] = attr_name;
249
250         va_start(ap, format);
251         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
252         va_end(ap);
253
254         if (count != 1) {
255                 return default_value;
256         }
257
258         return samdb_result_int64(res[0], attr_name, default_value);
259 }
260
261 /*
262   search the sam for multipe records each giving a single string attribute
263   return the number of matches, or -1 on error
264 */
265 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
266                                  TALLOC_CTX *mem_ctx,
267                                  struct ldb_dn *basedn,
268                                  const char ***strs,
269                                  const char *attr_name,
270                                  const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
271 {
272         va_list ap;
273         int count, i;
274         const char *attrs[2] = { NULL, NULL };
275         struct ldb_message **res = NULL;
276
277         attrs[0] = attr_name;
278
279         va_start(ap, format);
280         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
281         va_end(ap);
282
283         if (count <= 0) {
284                 return count;
285         }
286
287         /* make sure its single valued */
288         for (i=0;i<count;i++) {
289                 if (res[i]->num_elements != 1) {
290                         DEBUG(1,("samdb: search for %s %s not single valued\n", 
291                                  attr_name, format));
292                         talloc_free(res);
293                         return -1;
294                 }
295         }
296
297         *strs = talloc_array(mem_ctx, const char *, count+1);
298         if (! *strs) {
299                 talloc_free(res);
300                 return -1;
301         }
302
303         for (i=0;i<count;i++) {
304                 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
305         }
306         (*strs)[count] = NULL;
307
308         return count;
309 }
310
311 /*
312   pull a uint from a result set. 
313 */
314 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
315 {
316         return ldb_msg_find_attr_as_uint(msg, attr, default_value);
317 }
318
319 /*
320   pull a (signed) int64 from a result set. 
321 */
322 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
323 {
324         return ldb_msg_find_attr_as_int64(msg, attr, default_value);
325 }
326
327 /*
328   pull a string from a result set. 
329 */
330 const char *samdb_result_string(const struct ldb_message *msg, const char *attr, 
331                                 const char *default_value)
332 {
333         return ldb_msg_find_attr_as_string(msg, attr, default_value);
334 }
335
336 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
337                                const char *attr, struct ldb_dn *default_value)
338 {
339         struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
340         if (!ret_dn) {
341                 return default_value;
342         }
343         return ret_dn;
344 }
345
346 /*
347   pull a rid from a objectSid in a result set. 
348 */
349 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
350                                    const char *attr, uint32_t default_value)
351 {
352         struct dom_sid *sid;
353         uint32_t rid;
354
355         sid = samdb_result_dom_sid(mem_ctx, msg, attr);
356         if (sid == NULL) {
357                 return default_value;
358         }
359         rid = sid->sub_auths[sid->num_auths-1];
360         talloc_free(sid);
361         return rid;
362 }
363
364 /*
365   pull a dom_sid structure from a objectSid in a result set. 
366 */
367 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
368                                      const char *attr)
369 {
370         const struct ldb_val *v;
371         struct dom_sid *sid;
372         enum ndr_err_code ndr_err;
373         v = ldb_msg_find_ldb_val(msg, attr);
374         if (v == NULL) {
375                 return NULL;
376         }
377         sid = talloc(mem_ctx, struct dom_sid);
378         if (sid == NULL) {
379                 return NULL;
380         }
381         ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
382                                        (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
383         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
384                 talloc_free(sid);
385                 return NULL;
386         }
387         return sid;
388 }
389
390 /*
391   pull a guid structure from a objectGUID in a result set. 
392 */
393 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
394 {
395         const struct ldb_val *v;
396         enum ndr_err_code ndr_err;
397         struct GUID guid;
398         TALLOC_CTX *mem_ctx;
399
400         ZERO_STRUCT(guid);
401
402         v = ldb_msg_find_ldb_val(msg, attr);
403         if (!v) return guid;
404
405         mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
406         if (!mem_ctx) return guid;
407         ndr_err = ndr_pull_struct_blob(v, mem_ctx, NULL, &guid,
408                                        (ndr_pull_flags_fn_t)ndr_pull_GUID);
409         talloc_free(mem_ctx);
410         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
411                 return guid;
412         }
413
414         return guid;
415 }
416
417 /*
418   pull a sid prefix from a objectSid in a result set. 
419   this is used to find the domain sid for a user
420 */
421 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
422                                         const char *attr)
423 {
424         struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
425         if (!sid || sid->num_auths < 1) return NULL;
426         sid->num_auths--;
427         return sid;
428 }
429
430 /*
431   pull a NTTIME in a result set. 
432 */
433 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
434 {
435         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
436 }
437
438 /*
439  * Windows stores 0 for lastLogoff.
440  * But when a MS DC return the lastLogoff (as Logoff Time)
441  * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
442  * cause windows 2008 and newer version to fail for SMB requests
443  */
444 NTTIME samdb_result_last_logoff(struct ldb_message *msg)
445 {
446         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
447
448         if (ret == 0)
449                 ret = 0x7FFFFFFFFFFFFFFFULL;
450
451         return ret;
452 }
453
454 /*
455  * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
456  * indicate an account doesn't expire.
457  *
458  * When Windows initially creates an account, it sets
459  * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF).  However,
460  * when changing from an account having a specific expiration date to
461  * that account never expiring, it sets accountExpires = 0.
462  *
463  * Consolidate that logic here to allow clearer logic for account expiry in
464  * the rest of the code.
465  */
466 NTTIME samdb_result_account_expires(struct ldb_message *msg)
467 {
468         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
469                                                  0);
470
471         if (ret == 0)
472                 ret = 0x7FFFFFFFFFFFFFFFULL;
473
474         return ret;
475 }
476
477 /*
478   pull a uint64_t from a result set. 
479 */
480 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
481 {
482         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
483 }
484
485
486 /*
487   construct the allow_password_change field from the PwdLastSet attribute and the 
488   domain password settings
489 */
490 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb, 
491                                           TALLOC_CTX *mem_ctx, 
492                                           struct ldb_dn *domain_dn, 
493                                           struct ldb_message *msg, 
494                                           const char *attr)
495 {
496         uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
497         int64_t minPwdAge;
498
499         if (attr_time == 0) {
500                 return 0;
501         }
502
503         minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
504
505         /* yes, this is a -= not a += as minPwdAge is stored as the negative
506            of the number of 100-nano-seconds */
507         attr_time -= minPwdAge;
508
509         return attr_time;
510 }
511
512 /*
513   construct the force_password_change field from the PwdLastSet
514   attribute, the userAccountControl and the domain password settings
515 */
516 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb, 
517                                           TALLOC_CTX *mem_ctx, 
518                                           struct ldb_dn *domain_dn, 
519                                           struct ldb_message *msg)
520 {
521         uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
522         uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
523         int64_t maxPwdAge;
524
525         /* Machine accounts don't expire, and there is a flag for 'no expiry' */
526         if (!(userAccountControl & UF_NORMAL_ACCOUNT)
527             || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
528                 return 0x7FFFFFFFFFFFFFFFULL;
529         }
530
531         if (attr_time == 0) {
532                 return 0;
533         }
534
535         maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
536         if (maxPwdAge == 0) {
537                 return 0x7FFFFFFFFFFFFFFFULL;
538         } else {
539                 attr_time -= maxPwdAge;
540         }
541
542         return attr_time;
543 }
544
545 /*
546   pull a samr_Password structutre from a result set. 
547 */
548 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
549 {
550         struct samr_Password *hash = NULL;
551         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
552         if (val && (val->length >= sizeof(hash->hash))) {
553                 hash = talloc(mem_ctx, struct samr_Password);
554                 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
555         }
556         return hash;
557 }
558
559 /*
560   pull an array of samr_Password structutres from a result set. 
561 */
562 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
563                            const char *attr, struct samr_Password **hashes)
564 {
565         uint_t count = 0;
566         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
567         int i;
568
569         *hashes = NULL;
570         if (!val) {
571                 return 0;
572         }
573         count = val->length / 16;
574         if (count == 0) {
575                 return 0;
576         }
577
578         *hashes = talloc_array(mem_ctx, struct samr_Password, count);
579         if (! *hashes) {
580                 return 0;
581         }
582
583         for (i=0;i<count;i++) {
584                 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
585         }
586
587         return count;
588 }
589
590 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg, 
591                                 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd) 
592 {
593         struct samr_Password *lmPwdHash, *ntPwdHash;
594         if (nt_pwd) {
595                 int num_nt;
596                 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
597                 if (num_nt == 0) {
598                         *nt_pwd = NULL;
599                 } else if (num_nt > 1) {
600                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
601                 } else {
602                         *nt_pwd = &ntPwdHash[0];
603                 }
604         }
605         if (lm_pwd) {
606                 /* Ensure that if we have turned off LM
607                  * authentication, that we never use the LM hash, even
608                  * if we store it */
609                 if (lp_lanman_auth(lp_ctx)) {
610                         int num_lm;
611                         num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
612                         if (num_lm == 0) {
613                                 *lm_pwd = NULL;
614                         } else if (num_lm > 1) {
615                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
616                         } else {
617                                 *lm_pwd = &lmPwdHash[0];
618                         }
619                 } else {
620                         *lm_pwd = NULL;
621                 }
622         }
623         return NT_STATUS_OK;
624 }
625
626 /*
627   pull a samr_LogonHours structutre from a result set. 
628 */
629 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
630 {
631         struct samr_LogonHours hours;
632         const int units_per_week = 168;
633         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
634         ZERO_STRUCT(hours);
635         hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
636         if (!hours.bits) {
637                 return hours;
638         }
639         hours.units_per_week = units_per_week;
640         memset(hours.bits, 0xFF, units_per_week);
641         if (val) {
642                 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
643         }
644         return hours;
645 }
646
647 /*
648   pull a set of account_flags from a result set. 
649
650   This requires that the attributes: 
651    pwdLastSet
652    userAccountControl
653   be included in 'msg'
654 */
655 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
656                                  struct ldb_message *msg, struct ldb_dn *domain_dn)
657 {
658         uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
659         uint32_t acct_flags = ds_uf2acb(userAccountControl);
660         NTTIME must_change_time;
661         NTTIME now;
662
663         must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx, 
664                                                               domain_dn, msg);
665
666         /* Test account expire time */
667         unix_to_nt_time(&now, time(NULL));
668         /* check for expired password */
669         if (must_change_time < now) {
670                 acct_flags |= ACB_PW_EXPIRED;
671         }
672         return acct_flags;
673 }
674
675 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
676                                                 struct ldb_message *msg,
677                                                 const char *attr)
678 {
679         struct lsa_BinaryString s;
680         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
681
682         ZERO_STRUCT(s);
683
684         if (!val) {
685                 return s;
686         }
687
688         s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
689         if (!s.array) {
690                 return s;
691         }
692         s.length = s.size = val->length/2;
693         memcpy(s.array, val->data, val->length);
694
695         return s;
696 }
697
698 /* Find an attribute, with a particular value */
699
700 /* The current callers of this function expect a very specific
701  * behaviour: In particular, objectClass subclass equivilance is not
702  * wanted.  This means that we should not lookup the schema for the
703  * comparison function */
704 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb, 
705                                                  const struct ldb_message *msg, 
706                                                  const char *name, const char *value)
707 {
708         int i;
709         struct ldb_message_element *el = ldb_msg_find_element(msg, name);
710
711         if (!el) {
712                 return NULL;
713         }
714
715         for (i=0;i<el->num_values;i++) {
716                 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
717                         return el;
718                 }
719         }
720
721         return NULL;
722 }
723
724 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
725 {
726         if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
727                 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
728         }
729         return LDB_SUCCESS;
730 }
731
732 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
733 {
734         struct ldb_message_element *el;
735
736         el = ldb_msg_find_element(msg, name);
737         if (el) {
738                 return LDB_SUCCESS;
739         }
740
741         return samdb_msg_add_string(ldb, msg, msg, name, set_value);
742 }
743
744
745
746 /*
747   add a string element to a message
748 */
749 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
750                          const char *attr_name, const char *str)
751 {
752         char *s = talloc_strdup(mem_ctx, str);
753         char *a = talloc_strdup(mem_ctx, attr_name);
754         if (s == NULL || a == NULL) {
755                 return LDB_ERR_OPERATIONS_ERROR;
756         }
757         return ldb_msg_add_string(msg, a, s);
758 }
759
760 /*
761   add a dom_sid element to a message
762 */
763 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
764                          const char *attr_name, struct dom_sid *sid)
765 {
766         struct ldb_val v;
767         enum ndr_err_code ndr_err;
768
769         ndr_err = ndr_push_struct_blob(&v, mem_ctx, 
770                                        lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
771                                        sid,
772                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
773         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
774                 return -1;
775         }
776         return ldb_msg_add_value(msg, attr_name, &v, NULL);
777 }
778
779
780 /*
781   add a delete element operation to a message
782 */
783 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
784                          const char *attr_name)
785 {
786         /* we use an empty replace rather than a delete, as it allows for 
787            samdb_replace() to be used everywhere */
788         return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
789 }
790
791 /*
792   add a add attribute value to a message
793 */
794 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
795                          const char *attr_name, const char *value)
796 {
797         struct ldb_message_element *el;
798         char *a, *v;
799         int ret;
800         a = talloc_strdup(mem_ctx, attr_name);
801         if (a == NULL)
802                 return -1;
803         v = talloc_strdup(mem_ctx, value);
804         if (v == NULL)
805                 return -1;
806         ret = ldb_msg_add_string(msg, a, v);
807         if (ret != 0)
808                 return ret;
809         el = ldb_msg_find_element(msg, a);
810         if (el == NULL)
811                 return -1;
812         el->flags = LDB_FLAG_MOD_ADD;
813         return 0;
814 }
815
816 /*
817   add a delete attribute value to a message
818 */
819 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
820                          const char *attr_name, const char *value)
821 {
822         struct ldb_message_element *el;
823         char *a, *v;
824         int ret;
825         a = talloc_strdup(mem_ctx, attr_name);
826         if (a == NULL)
827                 return -1;
828         v = talloc_strdup(mem_ctx, value);
829         if (v == NULL)
830                 return -1;
831         ret = ldb_msg_add_string(msg, a, v);
832         if (ret != 0)
833                 return ret;
834         el = ldb_msg_find_element(msg, a);
835         if (el == NULL)
836                 return -1;
837         el->flags = LDB_FLAG_MOD_DELETE;
838         return 0;
839 }
840
841 /*
842   add a int element to a message
843 */
844 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
845                        const char *attr_name, int v)
846 {
847         const char *s = talloc_asprintf(mem_ctx, "%d", v);
848         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
849 }
850
851 /*
852   add a uint_t element to a message
853 */
854 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
855                        const char *attr_name, uint_t v)
856 {
857         const char *s = talloc_asprintf(mem_ctx, "%u", v);
858         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
859 }
860
861 /*
862   add a (signed) int64_t element to a message
863 */
864 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
865                         const char *attr_name, int64_t v)
866 {
867         const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
868         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
869 }
870
871 /*
872   add a uint64_t element to a message
873 */
874 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
875                         const char *attr_name, uint64_t v)
876 {
877         const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
878         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
879 }
880
881 /*
882   add a samr_Password element to a message
883 */
884 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
885                        const char *attr_name, struct samr_Password *hash)
886 {
887         struct ldb_val val;
888         val.data = talloc_memdup(mem_ctx, hash->hash, 16);
889         if (!val.data) {
890                 return -1;
891         }
892         val.length = 16;
893         return ldb_msg_add_value(msg, attr_name, &val, NULL);
894 }
895
896 /*
897   add a samr_Password array to a message
898 */
899 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
900                          const char *attr_name, struct samr_Password *hashes, uint_t count)
901 {
902         struct ldb_val val;
903         int i;
904         val.data = talloc_array_size(mem_ctx, 16, count);
905         val.length = count*16;
906         if (!val.data) {
907                 return -1;
908         }
909         for (i=0;i<count;i++) {
910                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
911         }
912         return ldb_msg_add_value(msg, attr_name, &val, NULL);
913 }
914
915 /*
916   add a acct_flags element to a message
917 */
918 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
919                              const char *attr_name, uint32_t v)
920 {
921         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
922 }
923
924 /*
925   add a logon_hours element to a message
926 */
927 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
928                               const char *attr_name, struct samr_LogonHours *hours)
929 {
930         struct ldb_val val;
931         val.length = hours->units_per_week / 8;
932         val.data = hours->bits;
933         return ldb_msg_add_value(msg, attr_name, &val, NULL);
934 }
935
936 /*
937   add a parameters element to a message
938 */
939 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
940                              const char *attr_name, struct lsa_BinaryString *parameters)
941 {
942         struct ldb_val val;
943         val.length = parameters->length * 2;
944         val.data = (uint8_t *)parameters->array;
945         return ldb_msg_add_value(msg, attr_name, &val, NULL);
946 }
947 /*
948   add a general value element to a message
949 */
950 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
951                               const char *attr_name, const struct ldb_val *val)
952 {
953         return ldb_msg_add_value(msg, attr_name, val, NULL);
954 }
955
956 /*
957   sets a general value element to a message
958 */
959 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
960                         const char *attr_name, const struct ldb_val *val)
961 {
962         struct ldb_message_element *el;
963
964         el = ldb_msg_find_element(msg, attr_name);
965         if (el) {
966                 el->num_values = 0;
967         }
968         return ldb_msg_add_value(msg, attr_name, val, NULL);
969 }
970
971 /*
972   set a string element in a message
973 */
974 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
975                          const char *attr_name, const char *str)
976 {
977         struct ldb_message_element *el;
978
979         el = ldb_msg_find_element(msg, attr_name);
980         if (el) {
981                 el->num_values = 0;
982         }
983         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
984 }
985
986 /*
987   replace elements in a record
988 */
989 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
990 {
991         int i;
992
993         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
994         for (i=0;i<msg->num_elements;i++) {
995                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
996         }
997
998         /* modify the samdb record */
999         return ldb_modify(sam_ldb, msg);
1000 }
1001
1002 /*
1003   return a default security descriptor
1004 */
1005 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1006 {
1007         struct security_descriptor *sd;
1008
1009         sd = security_descriptor_initialise(mem_ctx);
1010
1011         return sd;
1012 }
1013
1014 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx) 
1015 {
1016         return ldb_get_default_basedn(sam_ctx);
1017 }
1018
1019 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx) 
1020 {
1021         return ldb_get_config_basedn(sam_ctx);
1022 }
1023
1024 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx) 
1025 {
1026         return ldb_get_schema_basedn(sam_ctx);
1027 }
1028
1029 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx) 
1030 {
1031         return ldb_get_root_basedn(sam_ctx);
1032 }
1033
1034 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1035 {
1036         struct ldb_dn *new_dn;
1037
1038         new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1039         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1040                 talloc_free(new_dn);
1041                 return NULL;
1042         }
1043         return new_dn;
1044 }
1045
1046 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1047 {
1048         struct ldb_dn *new_dn;
1049
1050         new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1051         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1052                 talloc_free(new_dn);
1053                 return NULL;
1054         }
1055         return new_dn;
1056 }
1057
1058 /*
1059   work out the domain sid for the current open ldb
1060 */
1061 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1062 {
1063         TALLOC_CTX *tmp_ctx;
1064         const struct dom_sid *domain_sid;
1065         const char *attrs[] = {
1066                 "objectSid",
1067                 NULL
1068         };
1069         struct ldb_result *res;
1070         int ret;
1071
1072         /* see if we have a cached copy */
1073         domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1074         if (domain_sid) {
1075                 return domain_sid;
1076         }
1077
1078         tmp_ctx = talloc_new(ldb);
1079         if (tmp_ctx == NULL) {
1080                 goto failed;
1081         }
1082
1083         ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1084
1085         if (ret != LDB_SUCCESS) {
1086                 goto failed;
1087         }
1088
1089         if (res->count != 1) {
1090                 goto failed;
1091         }
1092
1093         domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1094         if (domain_sid == NULL) {
1095                 goto failed;
1096         }
1097
1098         /* cache the domain_sid in the ldb */
1099         if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1100                 goto failed;
1101         }
1102
1103         talloc_steal(ldb, domain_sid);
1104         talloc_free(tmp_ctx);
1105
1106         return domain_sid;
1107
1108 failed:
1109         DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1110         talloc_free(tmp_ctx);
1111         return NULL;
1112 }
1113
1114 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1115 {
1116         TALLOC_CTX *tmp_ctx;
1117         struct dom_sid *dom_sid_new;
1118         struct dom_sid *dom_sid_old;
1119
1120         /* see if we have a cached copy */
1121         dom_sid_old = talloc_get_type(ldb_get_opaque(ldb, 
1122                                                      "cache.domain_sid"), struct dom_sid);
1123
1124         tmp_ctx = talloc_new(ldb);
1125         if (tmp_ctx == NULL) {
1126                 goto failed;
1127         }
1128
1129         dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1130         if (!dom_sid_new) {
1131                 goto failed;
1132         }
1133
1134         /* cache the domain_sid in the ldb */
1135         if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1136                 goto failed;
1137         }
1138
1139         talloc_steal(ldb, dom_sid_new);
1140         talloc_free(tmp_ctx);
1141         talloc_free(dom_sid_old);
1142
1143         return true;
1144
1145 failed:
1146         DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1147         talloc_free(tmp_ctx);
1148         return false;
1149 }
1150
1151 /* Obtain the short name of the flexible single master operator
1152  * (FSMO), such as the PDC Emulator */
1153 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
1154                              const char *attr)
1155 {
1156         /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1157         struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1158         const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1159         const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1160
1161         if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1162                 /* Ensure this matches the format.  This gives us a
1163                  * bit more confidence that a 'cn' value will be a
1164                  * ascii string */
1165                 return NULL;
1166         }
1167         if (val) {
1168                 return (char *)val->data;
1169         }
1170         return NULL;
1171 }
1172
1173 /*
1174   work out the ntds settings dn for the current open ldb
1175 */
1176 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1177 {
1178         TALLOC_CTX *tmp_ctx;
1179         const char *root_attrs[] = { "dsServiceName", NULL };
1180         int ret;
1181         struct ldb_result *root_res;
1182         struct ldb_dn *settings_dn;
1183
1184         /* see if we have a cached copy */
1185         settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1186         if (settings_dn) {
1187                 return settings_dn;
1188         }
1189
1190         tmp_ctx = talloc_new(ldb);
1191         if (tmp_ctx == NULL) {
1192                 goto failed;
1193         }
1194
1195         ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1196         if (ret) {
1197                 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n", 
1198                          ldb_errstring(ldb)));
1199                 goto failed;
1200         }
1201
1202         if (root_res->count != 1) {
1203                 goto failed;
1204         }
1205
1206         settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1207
1208         /* cache the domain_sid in the ldb */
1209         if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1210                 goto failed;
1211         }
1212
1213         talloc_steal(ldb, settings_dn);
1214         talloc_free(tmp_ctx);
1215
1216         return settings_dn;
1217
1218 failed:
1219         DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1220         talloc_free(tmp_ctx);
1221         return NULL;
1222 }
1223
1224 /*
1225   work out the ntds settings invocationId for the current open ldb
1226 */
1227 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1228 {
1229         TALLOC_CTX *tmp_ctx;
1230         const char *attrs[] = { "invocationId", NULL };
1231         int ret;
1232         struct ldb_result *res;
1233         struct GUID *invocation_id;
1234
1235         /* see if we have a cached copy */
1236         invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1237         if (invocation_id) {
1238                 return invocation_id;
1239         }
1240
1241         tmp_ctx = talloc_new(ldb);
1242         if (tmp_ctx == NULL) {
1243                 goto failed;
1244         }
1245
1246         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1247         if (ret) {
1248                 goto failed;
1249         }
1250
1251         if (res->count != 1) {
1252                 goto failed;
1253         }
1254
1255         invocation_id = talloc(tmp_ctx, struct GUID);
1256         if (!invocation_id) {
1257                 goto failed;
1258         }
1259
1260         *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1261
1262         /* cache the domain_sid in the ldb */
1263         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1264                 goto failed;
1265         }
1266
1267         talloc_steal(ldb, invocation_id);
1268         talloc_free(tmp_ctx);
1269
1270         return invocation_id;
1271
1272 failed:
1273         DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1274         talloc_free(tmp_ctx);
1275         return NULL;
1276 }
1277
1278 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1279 {
1280         TALLOC_CTX *tmp_ctx;
1281         struct GUID *invocation_id_new;
1282         struct GUID *invocation_id_old;
1283
1284         /* see if we have a cached copy */
1285         invocation_id_old = (struct GUID *)ldb_get_opaque(ldb, 
1286                                                          "cache.invocation_id");
1287
1288         tmp_ctx = talloc_new(ldb);
1289         if (tmp_ctx == NULL) {
1290                 goto failed;
1291         }
1292
1293         invocation_id_new = talloc(tmp_ctx, struct GUID);
1294         if (!invocation_id_new) {
1295                 goto failed;
1296         }
1297
1298         *invocation_id_new = *invocation_id_in;
1299
1300         /* cache the domain_sid in the ldb */
1301         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1302                 goto failed;
1303         }
1304
1305         talloc_steal(ldb, invocation_id_new);
1306         talloc_free(tmp_ctx);
1307         talloc_free(invocation_id_old);
1308
1309         return true;
1310
1311 failed:
1312         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1313         talloc_free(tmp_ctx);
1314         return false;
1315 }
1316
1317 /*
1318   work out the ntds settings objectGUID for the current open ldb
1319 */
1320 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1321 {
1322         TALLOC_CTX *tmp_ctx;
1323         const char *attrs[] = { "objectGUID", NULL };
1324         int ret;
1325         struct ldb_result *res;
1326         struct GUID *ntds_guid;
1327
1328         /* see if we have a cached copy */
1329         ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1330         if (ntds_guid) {
1331                 return ntds_guid;
1332         }
1333
1334         tmp_ctx = talloc_new(ldb);
1335         if (tmp_ctx == NULL) {
1336                 goto failed;
1337         }
1338
1339         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1340         if (ret) {
1341                 goto failed;
1342         }
1343
1344         if (res->count != 1) {
1345                 goto failed;
1346         }
1347
1348         ntds_guid = talloc(tmp_ctx, struct GUID);
1349         if (!ntds_guid) {
1350                 goto failed;
1351         }
1352
1353         *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1354
1355         /* cache the domain_sid in the ldb */
1356         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1357                 goto failed;
1358         }
1359
1360         talloc_steal(ldb, ntds_guid);
1361         talloc_free(tmp_ctx);
1362
1363         return ntds_guid;
1364
1365 failed:
1366         DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1367         talloc_free(tmp_ctx);
1368         return NULL;
1369 }
1370
1371 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1372 {
1373         TALLOC_CTX *tmp_ctx;
1374         struct GUID *ntds_guid_new;
1375         struct GUID *ntds_guid_old;
1376
1377         /* see if we have a cached copy */
1378         ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1379
1380         tmp_ctx = talloc_new(ldb);
1381         if (tmp_ctx == NULL) {
1382                 goto failed;
1383         }
1384
1385         ntds_guid_new = talloc(tmp_ctx, struct GUID);
1386         if (!ntds_guid_new) {
1387                 goto failed;
1388         }
1389
1390         *ntds_guid_new = *ntds_guid_in;
1391
1392         /* cache the domain_sid in the ldb */
1393         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1394                 goto failed;
1395         }
1396
1397         talloc_steal(ldb, ntds_guid_new);
1398         talloc_free(tmp_ctx);
1399         talloc_free(ntds_guid_old);
1400
1401         return true;
1402
1403 failed:
1404         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1405         talloc_free(tmp_ctx);
1406         return false;
1407 }
1408
1409 /*
1410   work out the server dn for the current open ldb
1411 */
1412 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1413 {
1414         return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1415 }
1416
1417 /*
1418   work out the server dn for the current open ldb
1419 */
1420 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1421 {
1422         struct ldb_dn *server_dn;
1423         struct ldb_dn *server_site_dn;
1424
1425         server_dn = samdb_server_dn(ldb, mem_ctx);
1426         if (!server_dn) return NULL;
1427
1428         server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1429
1430         talloc_free(server_dn);
1431         return server_site_dn;
1432 }
1433
1434 /*
1435   work out if we are the PDC for the domain of the current open ldb
1436 */
1437 bool samdb_is_pdc(struct ldb_context *ldb)
1438 {
1439         const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1440         int ret;
1441         struct ldb_result *dom_res;
1442         TALLOC_CTX *tmp_ctx;
1443         bool is_pdc;
1444         struct ldb_dn *pdc;
1445
1446         tmp_ctx = talloc_new(ldb);
1447         if (tmp_ctx == NULL) {
1448                 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1449                 return false;
1450         }
1451
1452         ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1453         if (ret) {
1454                 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n", 
1455                          ldb_dn_get_linearized(ldb_get_default_basedn(ldb)), 
1456                          ldb_errstring(ldb)));
1457                 goto failed;
1458         }
1459         if (dom_res->count != 1) {
1460                 goto failed;
1461         }
1462
1463         pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1464
1465         if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1466                 is_pdc = true;
1467         } else {
1468                 is_pdc = false;
1469         }
1470
1471         talloc_free(tmp_ctx);
1472
1473         return is_pdc;
1474
1475 failed:
1476         DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1477         talloc_free(tmp_ctx);
1478         return false;
1479 }
1480
1481 /*
1482   work out if we are a Global Catalog server for the domain of the current open ldb
1483 */
1484 bool samdb_is_gc(struct ldb_context *ldb)
1485 {
1486         const char *attrs[] = { "options", NULL };
1487         int ret, options;
1488         struct ldb_result *res;
1489         TALLOC_CTX *tmp_ctx;
1490
1491         tmp_ctx = talloc_new(ldb);
1492         if (tmp_ctx == NULL) {
1493                 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1494                 return false;
1495         }
1496
1497         /* Query cn=ntds settings,.... */
1498         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1499         if (ret) {
1500                 talloc_free(tmp_ctx);
1501                 return false;
1502         }
1503         if (res->count != 1) {
1504                 talloc_free(tmp_ctx);
1505                 return false;
1506         }
1507
1508         options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1509         talloc_free(tmp_ctx);
1510
1511         /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1512         if (options & 0x000000001) {
1513                 return true;
1514         }
1515         return false;
1516 }
1517
1518 /* Find a domain object in the parents of a particular DN.  */
1519 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1520                                    struct ldb_dn **parent_dn, const char **errstring)
1521 {
1522         TALLOC_CTX *local_ctx;
1523         struct ldb_dn *sdn = dn;
1524         struct ldb_result *res = NULL;
1525         int ret = 0;
1526         const char *attrs[] = { NULL };
1527
1528         local_ctx = talloc_new(mem_ctx);
1529         if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1530
1531         while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1532                 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1533                                  "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");
1534                 if (ret == LDB_SUCCESS) {
1535                         if (res->count == 1) {
1536                                 break;
1537                         }
1538                 } else {
1539                         break;
1540                 }
1541         }
1542
1543         if (ret != LDB_SUCCESS) {
1544                 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1545                                              ldb_dn_get_linearized(dn),
1546                                              ldb_dn_get_linearized(sdn),
1547                                              ldb_errstring(ldb));
1548                 talloc_free(local_ctx);
1549                 return ret;
1550         }
1551         if (res->count != 1) {
1552                 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1553                                              ldb_dn_get_linearized(dn));
1554                 talloc_free(local_ctx);
1555                 return LDB_ERR_CONSTRAINT_VIOLATION;
1556         }
1557
1558         *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1559         talloc_free(local_ctx);
1560         return ret;
1561 }
1562
1563
1564 /*
1565   set the user password using plaintext, obeying any user or domain
1566   password restrictions
1567
1568   note that this function doesn't actually store the result in the
1569   database, it just fills in the "mod" structure with ldb modify
1570   elements to setup the correct change when samdb_replace() is
1571   called. This allows the caller to combine the change with other
1572   changes (as is needed by some of the set user info levels)
1573
1574   The caller should probably have a transaction wrapping this
1575 */
1576 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1577                             struct ldb_dn *user_dn,
1578                             struct ldb_dn *domain_dn,
1579                             struct ldb_message *mod,
1580                             const DATA_BLOB *new_password,
1581                             struct samr_Password *lmNewHash, 
1582                             struct samr_Password *ntNewHash,
1583                             bool user_change,
1584                             enum samr_RejectReason *reject_reason,
1585                             struct samr_DomInfo1 **_dominfo)
1586 {
1587         const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory", 
1588                                             "ntPwdHistory", 
1589                                             "dBCSPwd", "unicodePwd", 
1590                                             "objectSid", 
1591                                             "pwdLastSet", NULL };
1592         const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength", 
1593                                               "maxPwdAge", "minPwdAge", 
1594                                               "minPwdLength", NULL };
1595         NTTIME pwdLastSet;
1596         int64_t minPwdAge;
1597         uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1598         uint_t userAccountControl;
1599         struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1600         struct samr_Password local_lmNewHash, local_ntNewHash;
1601         int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1602         struct dom_sid *domain_sid;
1603         struct ldb_message **res;
1604         bool restrictions;
1605         int count;
1606         time_t now = time(NULL);
1607         NTTIME now_nt;
1608         int i;
1609
1610         /* we need to know the time to compute password age */
1611         unix_to_nt_time(&now_nt, now);
1612
1613         /* pull all the user parameters */
1614         count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1615         if (count != 1) {
1616                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1617         }
1618         userAccountControl = samdb_result_uint(res[0],   "userAccountControl", 0);
1619         sambaLMPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1620                                                  "lmPwdHistory", &sambaLMPwdHistory);
1621         sambaNTPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1622                                                  "ntPwdHistory", &sambaNTPwdHistory);
1623         lmPwdHash =          samdb_result_hash(mem_ctx, res[0],   "dBCSPwd");
1624         ntPwdHash =          samdb_result_hash(mem_ctx, res[0],   "unicodePwd");
1625         pwdLastSet =         samdb_result_uint64(res[0], "pwdLastSet", 0);
1626
1627         /* Only non-trust accounts have restrictions (possibly this
1628          * test is the wrong way around, but I like to be restrictive
1629          * if possible */
1630         restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1631                                                |UF_WORKSTATION_TRUST_ACCOUNT
1632                                                |UF_SERVER_TRUST_ACCOUNT)); 
1633
1634         if (domain_dn) {
1635                 /* pull the domain parameters */
1636                 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1637                 if (count != 1) {
1638                         DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n", 
1639                                   ldb_dn_get_linearized(domain_dn),
1640                                   ldb_dn_get_linearized(user_dn)));
1641                         return NT_STATUS_NO_SUCH_DOMAIN;
1642                 }
1643         } else {
1644                 /* work out the domain sid, and pull the domain from there */
1645                 domain_sid =         samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1646                 if (domain_sid == NULL) {
1647                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1648                 }
1649
1650                 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs, 
1651                                      "(objectSid=%s)", 
1652                                      ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1653                 if (count != 1) {
1654                         DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n", 
1655                                   dom_sid_string(mem_ctx, domain_sid),
1656                                   ldb_dn_get_linearized(user_dn)));
1657                         return NT_STATUS_NO_SUCH_DOMAIN;
1658                 }
1659         }
1660
1661         pwdProperties =    samdb_result_uint(res[0],   "pwdProperties", 0);
1662         pwdHistoryLength = samdb_result_uint(res[0],   "pwdHistoryLength", 0);
1663         minPwdLength =     samdb_result_uint(res[0],   "minPwdLength", 0);
1664         minPwdAge =        samdb_result_int64(res[0],  "minPwdAge", 0);
1665
1666         if (userAccountControl & UF_PASSWD_NOTREQD) {
1667                 /* see [MS-ADTS] 2.2.15 */
1668                 minPwdLength = 0;
1669         }
1670
1671         if (_dominfo) {
1672                 struct samr_DomInfo1 *dominfo;
1673                 /* on failure we need to fill in the reject reasons */
1674                 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1675                 if (dominfo == NULL) {
1676                         return NT_STATUS_NO_MEMORY;
1677                 }
1678                 dominfo->min_password_length     = minPwdLength;
1679                 dominfo->password_properties     = pwdProperties;
1680                 dominfo->password_history_length = pwdHistoryLength;
1681                 dominfo->max_password_age        = minPwdAge;
1682                 dominfo->min_password_age        = minPwdAge;
1683                 *_dominfo = dominfo;
1684         }
1685
1686         if (restrictions && new_password) {
1687                 char *new_pass;
1688
1689                 /* check the various password restrictions */
1690                 if (restrictions && minPwdLength > utf16_len_n(new_password->data, new_password->length) / 2) {
1691                         if (reject_reason) {
1692                                 *reject_reason = SAMR_REJECT_TOO_SHORT;
1693                         }
1694                         return NT_STATUS_PASSWORD_RESTRICTION;
1695                 }
1696
1697                 /* Create the NT hash */
1698                 mdfour(local_ntNewHash.hash, new_password->data, new_password->length);
1699
1700                 ntNewHash = &local_ntNewHash;
1701
1702                 /* Only check complexity if we can convert it at all.  Assuming unconvertable passwords are 'strong' */
1703                 if (convert_string_talloc_convenience(mem_ctx,
1704                           lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")),
1705                           CH_UTF16, CH_UNIX,
1706                           new_password->data, new_password->length,
1707                           (void **)&new_pass, NULL, false)) {
1708
1709                         /* possibly check password complexity */
1710                         if (restrictions && (pwdProperties & DOMAIN_PASSWORD_COMPLEX) &&
1711                             !check_password_quality(new_pass)) {
1712                                 if (reject_reason) {
1713                                         *reject_reason = SAMR_REJECT_COMPLEXITY;
1714                                 }
1715                                 return NT_STATUS_PASSWORD_RESTRICTION;
1716                         }
1717
1718                         /* compute the new lm hashes (for checking history - case insenitivly!) */
1719                         if (E_deshash(new_pass, local_lmNewHash.hash)) {
1720                                 lmNewHash = &local_lmNewHash;
1721                         }
1722                 }
1723         }
1724
1725         if (restrictions && user_change) {
1726                 /* are all password changes disallowed? */
1727                 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1728                         if (reject_reason) {
1729                                 *reject_reason = SAMR_REJECT_OTHER;
1730                         }
1731                         return NT_STATUS_PASSWORD_RESTRICTION;
1732                 }
1733
1734                 /* can this user change password? */
1735                 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1736                         if (reject_reason) {
1737                                 *reject_reason = SAMR_REJECT_OTHER;
1738                         }
1739                         return NT_STATUS_PASSWORD_RESTRICTION;
1740                 }
1741
1742                 /* yes, this is a minus. The ages are in negative 100nsec units! */
1743                 if (pwdLastSet - minPwdAge > now_nt) {
1744                         if (reject_reason) {
1745                                 *reject_reason = SAMR_REJECT_OTHER;
1746                         }
1747                         return NT_STATUS_PASSWORD_RESTRICTION;
1748                 }
1749
1750                 /* check the immediately past password */
1751                 if (pwdHistoryLength > 0) {
1752                         if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1753                                 if (reject_reason) {
1754                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1755                                 }
1756                                 return NT_STATUS_PASSWORD_RESTRICTION;
1757                         }
1758                         if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1759                                 if (reject_reason) {
1760                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1761                                 }
1762                                 return NT_STATUS_PASSWORD_RESTRICTION;
1763                         }
1764                 }
1765
1766                 /* check the password history */
1767                 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1768                 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1769
1770                 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1771                         if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1772                                 if (reject_reason) {
1773                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1774                                 }
1775                                 return NT_STATUS_PASSWORD_RESTRICTION;
1776                         }
1777                 }
1778                 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1779                         if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1780                                 if (reject_reason) {
1781                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1782                                 }
1783                                 return NT_STATUS_PASSWORD_RESTRICTION;
1784                         }
1785                 }
1786         }
1787
1788 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1789
1790         /* the password is acceptable. Start forming the new fields */
1791         if (new_password) {
1792                 /* if we know the cleartext UTF16 password, then set it.
1793                  * Modules in ldb will set all the appropriate
1794                  * hashes */
1795                 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
1796         } else {
1797                 /* We don't have the cleartext, so delete the old one
1798                  * and set what we have of the hashes */
1799                 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword"));
1800
1801                 if (lmNewHash) {
1802                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1803                 } else {
1804                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1805                 }
1806
1807                 if (ntNewHash) {
1808                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1809                 } else {
1810                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1811                 }
1812         }
1813
1814         return NT_STATUS_OK;
1815 }
1816
1817
1818 /*
1819   set the user password using plaintext, obeying any user or domain
1820   password restrictions
1821
1822   This wrapper function takes a SID as input, rather than a user DN,
1823   and actually performs the password change
1824
1825 */
1826 NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1827                                 const struct dom_sid *user_sid,
1828                                 const DATA_BLOB *new_pass,
1829                                 struct samr_Password *lmNewHash, 
1830                                 struct samr_Password *ntNewHash,
1831                                 bool user_change,
1832                                 enum samr_RejectReason *reject_reason,
1833                                 struct samr_DomInfo1 **_dominfo) 
1834 {
1835         NTSTATUS nt_status;
1836         struct ldb_dn *user_dn;
1837         struct ldb_message *msg;
1838         int ret;
1839
1840         ret = ldb_transaction_start(ctx);
1841         if (ret) {
1842                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1843                 return NT_STATUS_TRANSACTION_ABORTED;
1844         }
1845
1846         user_dn = samdb_search_dn(ctx, mem_ctx, NULL, 
1847                                   "(&(objectSid=%s)(objectClass=user))", 
1848                                   ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1849         if (!user_dn) {
1850                 ldb_transaction_cancel(ctx);
1851                 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1852                           dom_sid_string(mem_ctx, user_sid)));
1853                 return NT_STATUS_NO_SUCH_USER;
1854         }
1855
1856         msg = ldb_msg_new(mem_ctx);
1857         if (msg == NULL) {
1858                 ldb_transaction_cancel(ctx);
1859                 return NT_STATUS_NO_MEMORY;
1860         }
1861
1862         msg->dn = ldb_dn_copy(msg, user_dn);
1863         if (!msg->dn) {
1864                 ldb_transaction_cancel(ctx);
1865                 return NT_STATUS_NO_MEMORY;
1866         }
1867
1868         nt_status = samdb_set_password(ctx, mem_ctx,
1869                                        user_dn, NULL,
1870                                        msg, new_pass, 
1871                                        lmNewHash, ntNewHash,
1872                                        user_change, /* This is a password set, not change */
1873                                        reject_reason, _dominfo);
1874         if (!NT_STATUS_IS_OK(nt_status)) {
1875                 ldb_transaction_cancel(ctx);
1876                 return nt_status;
1877         }
1878
1879         /* modify the samdb record */
1880         ret = samdb_replace(ctx, mem_ctx, msg);
1881         if (ret != 0) {
1882                 ldb_transaction_cancel(ctx);
1883                 return NT_STATUS_ACCESS_DENIED;
1884         }
1885
1886         ret = ldb_transaction_commit(ctx);
1887         if (ret != 0) {
1888                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1889                          ldb_dn_get_linearized(msg->dn),
1890                          ldb_errstring(ctx)));
1891                 return NT_STATUS_TRANSACTION_ABORTED;
1892         }
1893         return NT_STATUS_OK;
1894 }
1895
1896
1897
1898 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
1899                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
1900 {
1901         struct ldb_message *msg;
1902         struct ldb_dn *basedn;
1903         const char *sidstr;
1904         int ret;
1905
1906         sidstr = dom_sid_string(mem_ctx, sid);
1907         NT_STATUS_HAVE_NO_MEMORY(sidstr);
1908
1909         /* We might have to create a ForeignSecurityPrincipal, even if this user
1910          * is in our own domain */
1911
1912         msg = ldb_msg_new(mem_ctx);
1913         if (msg == NULL) {
1914                 return NT_STATUS_NO_MEMORY;
1915         }
1916
1917         /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1918          * put the ForeignSecurityPrincipals? d_state->domain_dn does
1919          * not work, this is wrong for the Builtin domain, there's no
1920          * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
1921          */
1922
1923         basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1924                                  "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1925
1926         if (basedn == NULL) {
1927                 DEBUG(0, ("Failed to find DN for "
1928                           "ForeignSecurityPrincipal container\n"));
1929                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1930         }
1931
1932         /* add core elements to the ldb_message for the alias */
1933         msg->dn = ldb_dn_copy(mem_ctx, basedn);
1934         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1935                 return NT_STATUS_NO_MEMORY;
1936
1937         samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1938                              "objectClass",
1939                              "foreignSecurityPrincipal");
1940
1941         /* create the alias */
1942         ret = ldb_add(sam_ctx, msg);
1943         if (ret != 0) {
1944                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1945                          "record %s: %s\n", 
1946                          ldb_dn_get_linearized(msg->dn),
1947                          ldb_errstring(sam_ctx)));
1948                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1949         }
1950         *ret_dn = msg->dn;
1951         return NT_STATUS_OK;
1952 }
1953
1954
1955 /*
1956   Find the DN of a domain, assuming it to be a dotted.dns name
1957 */
1958
1959 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) 
1960 {
1961         int i;
1962         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1963         const char *binary_encoded;
1964         const char **split_realm;
1965         struct ldb_dn *dn;
1966
1967         if (!tmp_ctx) {
1968                 return NULL;
1969         }
1970
1971         split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
1972         if (!split_realm) {
1973                 talloc_free(tmp_ctx);
1974                 return NULL;
1975         }
1976         dn = ldb_dn_new(mem_ctx, ldb, NULL);
1977         for (i=0; split_realm[i]; i++) {
1978                 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1979                 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1980                         DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1981                                   binary_encoded, ldb_dn_get_linearized(dn)));
1982                         talloc_free(tmp_ctx);
1983                         return NULL;
1984                 }
1985         }
1986         if (!ldb_dn_validate(dn)) {
1987                 DEBUG(2, ("Failed to validated DN %s\n",
1988                           ldb_dn_get_linearized(dn)));
1989                 return NULL;
1990         }
1991         return dn;
1992 }
1993 /*
1994   Find the DN of a domain, be it the netbios or DNS name 
1995 */
1996
1997 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
1998                                   const char *domain_name) 
1999 {
2000         const char * const domain_ref_attrs[] = {
2001                 "ncName", NULL
2002         };
2003         const char * const domain_ref2_attrs[] = {
2004                 NULL
2005         };
2006         struct ldb_result *res_domain_ref;
2007         char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2008         /* find the domain's DN */
2009         int ret_domain = ldb_search(ldb, mem_ctx,
2010                                             &res_domain_ref, 
2011                                             samdb_partitions_dn(ldb, mem_ctx), 
2012                                             LDB_SCOPE_ONELEVEL, 
2013                                             domain_ref_attrs,
2014                                             "(&(nETBIOSName=%s)(objectclass=crossRef))", 
2015                                             escaped_domain);
2016         if (ret_domain != 0) {
2017                 return NULL;
2018         }
2019
2020         if (res_domain_ref->count == 0) {
2021                 ret_domain = ldb_search(ldb, mem_ctx,
2022                                                 &res_domain_ref, 
2023                                                 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2024                                                 LDB_SCOPE_BASE,
2025                                                 domain_ref2_attrs,
2026                                                 "(objectclass=domain)");
2027                 if (ret_domain != 0) {
2028                         return NULL;
2029                 }
2030
2031                 if (res_domain_ref->count == 1) {
2032                         return res_domain_ref->msgs[0]->dn;
2033                 }
2034                 return NULL;
2035         }
2036
2037         if (res_domain_ref->count > 1) {
2038                 DEBUG(0,("Found %d records matching domain [%s]\n", 
2039                          ret_domain, domain_name));
2040                 return NULL;
2041         }
2042
2043         return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2044
2045 }
2046
2047
2048 /*
2049   use a GUID to find a DN
2050  */
2051 int dsdb_find_dn_by_guid(struct ldb_context *ldb, 
2052                          TALLOC_CTX *mem_ctx,
2053                          const char *guid_str, struct ldb_dn **dn)
2054 {
2055         int ret;
2056         struct ldb_result *res;
2057         const char *attrs[] = { NULL };
2058         struct ldb_request *search_req;
2059         char *expression;
2060         struct ldb_search_options_control *options;
2061
2062         expression = talloc_asprintf(mem_ctx, "objectGUID=%s", guid_str);
2063         if (!expression) {
2064                 DEBUG(0, (__location__ ": out of memory\n"));
2065                 return LDB_ERR_OPERATIONS_ERROR;
2066         }
2067
2068         res = talloc_zero(mem_ctx, struct ldb_result);
2069         if (!res) {
2070                 DEBUG(0, (__location__ ": out of memory\n"));
2071                 return LDB_ERR_OPERATIONS_ERROR;
2072         }
2073
2074         ret = ldb_build_search_req(&search_req, ldb, mem_ctx,
2075                                    ldb_get_default_basedn(ldb),
2076                                    LDB_SCOPE_SUBTREE,
2077                                    expression, attrs,
2078                                    NULL,
2079                                    res, ldb_search_default_callback,
2080                                    NULL);
2081         if (ret != LDB_SUCCESS) {
2082                 return ret;
2083         }
2084
2085         /* we need to cope with cross-partition links, so search for
2086            the GUID over all partitions */
2087         options = talloc(search_req, struct ldb_search_options_control);
2088         if (options == NULL) {
2089                 DEBUG(0, (__location__ ": out of memory\n"));
2090                 return LDB_ERR_OPERATIONS_ERROR;
2091         }
2092         options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2093
2094         ret = ldb_request_add_control(search_req,
2095                                       LDB_CONTROL_SEARCH_OPTIONS_OID,
2096                                       true, options);
2097         if (ret != LDB_SUCCESS) {
2098                 return ret;
2099         }
2100
2101         ret = ldb_request(ldb, search_req);
2102         if (ret != LDB_SUCCESS) {
2103                 return ret;
2104         }
2105
2106         ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
2107         if (ret != LDB_SUCCESS) {
2108                 return ret;
2109         }
2110
2111         /* this really should be exactly 1, but there is a bug in the
2112            partitions module that can return two here with the
2113            search_options control set */
2114         if (res->count < 1) {
2115                 return LDB_ERR_NO_SUCH_OBJECT;
2116         }
2117
2118         *dn = res->msgs[0]->dn;
2119
2120         return LDB_SUCCESS;
2121 }
2122
2123
2124 /*
2125   use a DN to find a GUID
2126  */
2127 int dsdb_find_guid_by_dn(struct ldb_context *ldb, 
2128                          struct ldb_dn *dn, struct GUID *guid)
2129 {
2130         int ret;
2131         struct ldb_result *res;
2132         const char *attrs[] = { "objectGUID", NULL };
2133         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2134
2135         ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL);
2136         if (ret != LDB_SUCCESS) {
2137                 talloc_free(tmp_ctx);
2138                 return ret;
2139         }
2140         *guid = samdb_result_guid(res->msgs[0], "objectGUID");
2141         talloc_free(tmp_ctx);
2142         return LDB_SUCCESS;
2143 }