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