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