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