r21362: rename:
[kai/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 2 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, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_netlogon.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "librpc/gen_ndr/ndr_security.h"
29 #include "lib/ldb/include/ldb.h"
30 #include "lib/ldb/include/ldb_errors.h"
31 #include "libcli/security/security.h"
32 #include "libcli/auth/libcli_auth.h"
33 #include "libcli/ldap/ldap.h"
34 #include "system/time.h"
35 #include "system/filesys.h"
36 #include "db_wrap.h"
37 #include "dsdb/samdb/samdb.h"
38 #include "dsdb/common/flags.h"
39
40 /*
41   connect to the SAM database
42   return an opaque context pointer on success, or NULL on failure
43  */
44 struct ldb_context *samdb_connect(TALLOC_CTX *mem_ctx, 
45                                   struct auth_session_info *session_info)
46 {
47         struct ldb_context *ldb;
48         ldb = ldb_wrap_connect(mem_ctx, lp_sam_url(), session_info,
49                                NULL, 0, NULL);
50         if (!ldb) {
51                 return NULL;
52         }
53         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 *filter,
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         /* pull the template record */
694         ret = ldb_search(ldb, basedn, LDB_SCOPE_SUBTREE, filter, NULL, &res);
695         talloc_free(basedn);
696         if (ret != LDB_SUCCESS) {
697                 *errstring = talloc_steal(msg, ldb_errstring(ldb));
698                 return ret;
699         }
700         if (res->count != 1) {
701                 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1\n", filter, 
702                                              res->count);
703                 talloc_free(res);
704                 return LDB_ERR_OPERATIONS_ERROR;
705         }
706         t = res->msgs[0];
707
708         for (i = 0; i < t->num_elements; i++) {
709                 struct ldb_message_element *el = &t->elements[i];
710                 /* some elements should not be copied from the template */
711                 if (strcasecmp(el->name, "cn") == 0 ||
712                     strcasecmp(el->name, "name") == 0 ||
713                     strcasecmp(el->name, "sAMAccountName") == 0 ||
714                     strcasecmp(el->name, "sAMAccountName") == 0 ||
715                     strcasecmp(el->name, "distinguishedName") == 0 ||
716                     strcasecmp(el->name, "objectGUID") == 0) {
717                         continue;
718                 }
719                 for (j = 0; j < el->num_values; j++) {
720                         if (strcasecmp(el->name, "objectClass") == 0) {
721                                 if (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
722                                     strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
723                                     strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
724                                     strcasecmp((char *)el->values[j].data, "foreignSecurityPrincipalTemplate") == 0 ||
725                                     strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 || 
726                                     strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 || 
727                                     strcasecmp((char *)el->values[j].data, "secretTemplate") == 0) {
728                                         continue;
729                                 }
730                                 ret = samdb_find_or_add_value(ldb, msg, el->name, 
731                                                               (char *)el->values[j].data);
732                                 if (ret) {
733                                         *errstring = talloc_asprintf(msg, "Adding objectClass %s failed.\n", el->values[j].data);
734                                         talloc_free(res);
735                                         return ret;
736                                 }
737                         } else {
738                                 ret = samdb_find_or_add_attribute(ldb, msg, el->name, 
739                                                                   (char *)el->values[j].data);
740                                 if (ret) {
741                                         *errstring = talloc_asprintf(msg, "Adding attribute %s failed.\n", el->name);
742                                         talloc_free(res);
743                                         return ret;
744                                 }
745                         }
746                 }
747         }
748
749         talloc_free(res);
750
751         return LDB_SUCCESS;
752 }
753
754
755 /*
756   add a string element to a message
757 */
758 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
759                          const char *attr_name, const char *str)
760 {
761         char *s = talloc_strdup(mem_ctx, str);
762         char *a = talloc_strdup(mem_ctx, attr_name);
763         if (s == NULL || a == NULL) {
764                 return LDB_ERR_OPERATIONS_ERROR;
765         }
766         return ldb_msg_add_string(msg, a, s);
767 }
768
769 /*
770   add a dom_sid element to a message
771 */
772 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
773                          const char *attr_name, struct dom_sid *sid)
774 {
775         struct ldb_val v;
776         NTSTATUS status;
777         status = ndr_push_struct_blob(&v, mem_ctx, sid, 
778                                       (ndr_push_flags_fn_t)ndr_push_dom_sid);
779         if (!NT_STATUS_IS_OK(status)) {
780                 return -1;
781         }
782         return ldb_msg_add_value(msg, attr_name, &v, NULL);
783 }
784
785
786 /*
787   add a delete element operation to a message
788 */
789 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
790                          const char *attr_name)
791 {
792         /* we use an empty replace rather than a delete, as it allows for 
793            samdb_replace() to be used everywhere */
794         return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
795 }
796
797 /*
798   add a add attribute value to a message
799 */
800 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
801                          const char *attr_name, const char *value)
802 {
803         struct ldb_message_element *el;
804         char *a, *v;
805         int ret;
806         a = talloc_strdup(mem_ctx, attr_name);
807         if (a == NULL)
808                 return -1;
809         v = talloc_strdup(mem_ctx, value);
810         if (v == NULL)
811                 return -1;
812         ret = ldb_msg_add_string(msg, a, v);
813         if (ret != 0)
814                 return ret;
815         el = ldb_msg_find_element(msg, a);
816         if (el == NULL)
817                 return -1;
818         el->flags = LDB_FLAG_MOD_ADD;
819         return 0;
820 }
821
822 /*
823   add a delete attribute value to a message
824 */
825 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
826                          const char *attr_name, const char *value)
827 {
828         struct ldb_message_element *el;
829         char *a, *v;
830         int ret;
831         a = talloc_strdup(mem_ctx, attr_name);
832         if (a == NULL)
833                 return -1;
834         v = talloc_strdup(mem_ctx, value);
835         if (v == NULL)
836                 return -1;
837         ret = ldb_msg_add_string(msg, a, v);
838         if (ret != 0)
839                 return ret;
840         el = ldb_msg_find_element(msg, a);
841         if (el == NULL)
842                 return -1;
843         el->flags = LDB_FLAG_MOD_DELETE;
844         return 0;
845 }
846
847 /*
848   add a int element to a message
849 */
850 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
851                        const char *attr_name, int v)
852 {
853         const char *s = talloc_asprintf(mem_ctx, "%d", v);
854         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
855 }
856
857 /*
858   add a uint_t element to a message
859 */
860 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
861                        const char *attr_name, uint_t v)
862 {
863         const char *s = talloc_asprintf(mem_ctx, "%u", v);
864         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
865 }
866
867 /*
868   add a (signed) int64_t element to a message
869 */
870 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
871                         const char *attr_name, int64_t v)
872 {
873         const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
874         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
875 }
876
877 /*
878   add a uint64_t element to a message
879 */
880 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
881                         const char *attr_name, uint64_t v)
882 {
883         const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
884         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
885 }
886
887 /*
888   add a samr_Password element to a message
889 */
890 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
891                        const char *attr_name, struct samr_Password *hash)
892 {
893         struct ldb_val val;
894         val.data = talloc_memdup(mem_ctx, hash->hash, 16);
895         if (!val.data) {
896                 return -1;
897         }
898         val.length = 16;
899         return ldb_msg_add_value(msg, attr_name, &val, NULL);
900 }
901
902 /*
903   add a samr_Password array to a message
904 */
905 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
906                          const char *attr_name, struct samr_Password *hashes, uint_t count)
907 {
908         struct ldb_val val;
909         int i;
910         val.data = talloc_array_size(mem_ctx, 16, count);
911         val.length = count*16;
912         if (!val.data) {
913                 return -1;
914         }
915         for (i=0;i<count;i++) {
916                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
917         }
918         return ldb_msg_add_value(msg, attr_name, &val, NULL);
919 }
920
921 /*
922   add a acct_flags element to a message
923 */
924 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
925                              const char *attr_name, uint32_t v)
926 {
927         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
928 }
929
930 /*
931   add a logon_hours element to a message
932 */
933 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
934                               const char *attr_name, struct samr_LogonHours *hours)
935 {
936         struct ldb_val val;
937         val.length = hours->units_per_week / 8;
938         val.data = hours->bits;
939         return ldb_msg_add_value(msg, attr_name, &val, NULL);
940 }
941
942 /*
943   add a general value element to a message
944 */
945 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
946                               const char *attr_name, const struct ldb_val *val)
947 {
948         return ldb_msg_add_value(msg, attr_name, val, NULL);
949 }
950
951 /*
952   sets a general value element to a message
953 */
954 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
955                         const char *attr_name, const struct ldb_val *val)
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 ldb_msg_add_value(msg, attr_name, val, NULL);
964 }
965
966 /*
967   set a string element in a message
968 */
969 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
970                          const char *attr_name, const char *str)
971 {
972         struct ldb_message_element *el;
973
974         el = ldb_msg_find_element(msg, attr_name);
975         if (el) {
976                 el->num_values = 0;
977         }
978         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
979 }
980
981 /*
982   add a record
983 */
984 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
985 {
986         return ldb_add(sam_ldb, msg);
987 }
988
989 /*
990   delete a record
991 */
992 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
993 {
994         return ldb_delete(sam_ldb, dn);
995 }
996
997 /*
998   modify a record
999 */
1000 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1001 {
1002         return ldb_modify(sam_ldb, msg);
1003 }
1004
1005 /*
1006   replace elements in a record
1007 */
1008 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1009 {
1010         int i;
1011
1012         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1013         for (i=0;i<msg->num_elements;i++) {
1014                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1015         }
1016
1017         /* modify the samdb record */
1018         return samdb_modify(sam_ldb, mem_ctx, msg);
1019 }
1020
1021 /*
1022   return a default security descriptor
1023 */
1024 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1025 {
1026         struct security_descriptor *sd;
1027
1028         sd = security_descriptor_initialise(mem_ctx);
1029
1030         return sd;
1031 }
1032
1033 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx) 
1034 {
1035         return ldb_get_default_basedn(sam_ctx);
1036 }
1037
1038 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx) 
1039 {
1040         return ldb_get_config_basedn(sam_ctx);
1041 }
1042
1043 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx) 
1044 {
1045         return ldb_get_schema_basedn(sam_ctx);
1046 }
1047
1048 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx) 
1049 {
1050         return ldb_get_root_basedn(sam_ctx);
1051 }
1052
1053 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1054 {
1055         struct ldb_dn *new_dn;
1056
1057         new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1058         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1059                 talloc_free(new_dn);
1060                 return NULL;
1061         }
1062         return new_dn;
1063 }
1064
1065 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1066 {
1067         struct ldb_dn *new_dn;
1068
1069         new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1070         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1071                 talloc_free(new_dn);
1072                 return NULL;
1073         }
1074         return new_dn;
1075 }
1076
1077 /*
1078   work out the domain sid for the current open ldb
1079 */
1080 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1081 {
1082         TALLOC_CTX *tmp_ctx;
1083         struct dom_sid *domain_sid;
1084
1085         /* see if we have a cached copy */
1086         domain_sid = ldb_get_opaque(ldb, "cache.domain_sid");
1087         if (domain_sid) {
1088                 return domain_sid;
1089         }
1090
1091         tmp_ctx = talloc_new(ldb);
1092         if (tmp_ctx == NULL) {
1093                 goto failed;
1094         }
1095
1096         /* find the domain_sid */
1097         domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
1098                                           "objectSid", "objectClass=domainDNS");
1099         if (domain_sid == NULL) {
1100                 goto failed;
1101         }
1102
1103         /* cache the domain_sid in the ldb */
1104         if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1105                 goto failed;
1106         }
1107
1108         talloc_steal(ldb, domain_sid);
1109         talloc_free(tmp_ctx);
1110
1111         return domain_sid;
1112
1113 failed:
1114         DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1115         talloc_free(tmp_ctx);
1116         return NULL;
1117 }
1118
1119 /* Obtain the short name of the flexible single master operator
1120  * (FSMO), such as the PDC Emulator */
1121 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
1122                              const char *attr)
1123 {
1124         /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1125         struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1126         const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1127         const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1128
1129         if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1130                 /* Ensure this matches the format.  This gives us a
1131                  * bit more confidence that a 'cn' value will be a
1132                  * ascii string */
1133                 return NULL;
1134         }
1135         if (val) {
1136                 return (char *)val->data;
1137         }
1138         return NULL;
1139 }
1140
1141 /*
1142   work out the ntds settings dn for the current open ldb
1143 */
1144 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1145 {
1146         TALLOC_CTX *tmp_ctx;
1147         const char *root_attrs[] = { "dsServiceName", NULL };
1148         int ret;
1149         struct ldb_result *root_res;
1150         struct ldb_dn *settings_dn;
1151         
1152         /* see if we have a cached copy */
1153         settings_dn = ldb_get_opaque(ldb, "cache.settings_dn");
1154         if (settings_dn) {
1155                 return settings_dn;
1156         }
1157
1158         tmp_ctx = talloc_new(ldb);
1159         if (tmp_ctx == NULL) {
1160                 goto failed;
1161         }
1162         
1163
1164         ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1165         if (ret) {
1166                 goto failed;
1167         }
1168         talloc_steal(tmp_ctx, root_res);
1169
1170         if (root_res->count != 1) {
1171                 goto failed;
1172         }
1173
1174         settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1175
1176         /* cache the domain_sid in the ldb */
1177         if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1178                 goto failed;
1179         }
1180
1181         talloc_steal(ldb, settings_dn);
1182         talloc_free(tmp_ctx);
1183
1184         return settings_dn;
1185
1186 failed:
1187         DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1188         talloc_free(tmp_ctx);
1189         return NULL;
1190 }
1191
1192 /*
1193   work out the ntds settings invocationId for the current open ldb
1194 */
1195 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1196 {
1197         TALLOC_CTX *tmp_ctx;
1198         const char *attrs[] = { "invocationId", NULL };
1199         int ret;
1200         struct ldb_result *res;
1201         struct GUID *invocation_id;
1202         
1203         /* see if we have a cached copy */
1204         invocation_id = ldb_get_opaque(ldb, "cache.invocation_id");
1205         if (invocation_id) {
1206                 return invocation_id;
1207         }
1208
1209         tmp_ctx = talloc_new(ldb);
1210         if (tmp_ctx == NULL) {
1211                 goto failed;
1212         }
1213
1214         ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1215         if (ret) {
1216                 goto failed;
1217         }
1218         talloc_steal(tmp_ctx, res);
1219
1220         if (res->count != 1) {
1221                 goto failed;
1222         }
1223
1224         invocation_id = talloc(tmp_ctx, struct GUID);
1225         if (!invocation_id) {
1226                 goto failed;
1227         }
1228
1229         *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1230
1231         /* cache the domain_sid in the ldb */
1232         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1233                 goto failed;
1234         }
1235
1236         talloc_steal(ldb, invocation_id);
1237         talloc_free(tmp_ctx);
1238
1239         return invocation_id;
1240
1241 failed:
1242         DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1243         talloc_free(tmp_ctx);
1244         return NULL;
1245 }
1246
1247 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1248 {
1249         TALLOC_CTX *tmp_ctx;
1250         struct GUID *invocation_id_new;
1251         struct GUID *invocation_id_old;
1252
1253         /* see if we have a cached copy */
1254         invocation_id_old = ldb_get_opaque(ldb, "cache.invocation_id");
1255
1256         tmp_ctx = talloc_new(ldb);
1257         if (tmp_ctx == NULL) {
1258                 goto failed;
1259         }
1260
1261         invocation_id_new = talloc(tmp_ctx, struct GUID);
1262         if (!invocation_id_new) {
1263                 goto failed;
1264         }
1265
1266         *invocation_id_new = *invocation_id_in;
1267
1268         /* cache the domain_sid in the ldb */
1269         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1270                 goto failed;
1271         }
1272
1273         talloc_steal(ldb, invocation_id_new);
1274         talloc_free(tmp_ctx);
1275         talloc_free(invocation_id_old);
1276
1277         return true;
1278
1279 failed:
1280         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1281         talloc_free(tmp_ctx);
1282         return false;
1283 }
1284
1285 /*
1286   work out the ntds settings objectGUID for the current open ldb
1287 */
1288 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1289 {
1290         TALLOC_CTX *tmp_ctx;
1291         const char *attrs[] = { "objectGUID", NULL };
1292         int ret;
1293         struct ldb_result *res;
1294         struct GUID *ntds_guid;
1295         
1296         /* see if we have a cached copy */
1297         ntds_guid = ldb_get_opaque(ldb, "cache.ntds_guid");
1298         if (ntds_guid) {
1299                 return ntds_guid;
1300         }
1301
1302         tmp_ctx = talloc_new(ldb);
1303         if (tmp_ctx == NULL) {
1304                 goto failed;
1305         }
1306
1307         ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1308         if (ret) {
1309                 goto failed;
1310         }
1311         talloc_steal(tmp_ctx, res);
1312
1313         if (res->count != 1) {
1314                 goto failed;
1315         }
1316
1317         ntds_guid = talloc(tmp_ctx, struct GUID);
1318         if (!ntds_guid) {
1319                 goto failed;
1320         }
1321
1322         *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1323
1324         /* cache the domain_sid in the ldb */
1325         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1326                 goto failed;
1327         }
1328
1329         talloc_steal(ldb, ntds_guid);
1330         talloc_free(tmp_ctx);
1331
1332         return ntds_guid;
1333
1334 failed:
1335         DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1336         talloc_free(tmp_ctx);
1337         return NULL;
1338 }
1339
1340 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1341 {
1342         TALLOC_CTX *tmp_ctx;
1343         struct GUID *ntds_guid_new;
1344         struct GUID *ntds_guid_old;
1345         
1346         /* see if we have a cached copy */
1347         ntds_guid_old = ldb_get_opaque(ldb, "cache.ntds_guid");
1348
1349         tmp_ctx = talloc_new(ldb);
1350         if (tmp_ctx == NULL) {
1351                 goto failed;
1352         }
1353
1354         ntds_guid_new = talloc(tmp_ctx, struct GUID);
1355         if (!ntds_guid_new) {
1356                 goto failed;
1357         }
1358
1359         *ntds_guid_new = *ntds_guid_in;
1360
1361         /* cache the domain_sid in the ldb */
1362         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1363                 goto failed;
1364         }
1365
1366         talloc_steal(ldb, ntds_guid_new);
1367         talloc_free(tmp_ctx);
1368         talloc_free(ntds_guid_old);
1369
1370         return true;
1371
1372 failed:
1373         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1374         talloc_free(tmp_ctx);
1375         return false;
1376 }
1377
1378 /*
1379   work out the server dn for the current open ldb
1380 */
1381 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1382 {
1383         return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1384 }
1385
1386 /*
1387   work out if we are the PDC for the domain of the current open ldb
1388 */
1389 BOOL samdb_is_pdc(struct ldb_context *ldb)
1390 {
1391         const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1392         int ret;
1393         struct ldb_result *dom_res;
1394         TALLOC_CTX *tmp_ctx;
1395         BOOL is_pdc;
1396         struct ldb_dn *pdc;
1397
1398         tmp_ctx = talloc_new(ldb);
1399         if (tmp_ctx == NULL) {
1400                 goto failed;
1401         }
1402
1403         ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1404         if (ret) {
1405                 goto failed;
1406         }
1407         talloc_steal(tmp_ctx, dom_res);
1408         if (dom_res->count != 1) {
1409                 goto failed;
1410         }
1411
1412         pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1413
1414         if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1415                 is_pdc = True;
1416         } else {
1417                 is_pdc = False;
1418         }
1419
1420         talloc_free(tmp_ctx);
1421
1422         return is_pdc;
1423
1424 failed:
1425         DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1426         talloc_free(tmp_ctx);
1427         return False;
1428 }
1429
1430
1431 /* Find a domain object in the parents of a particular DN.  */
1432 struct ldb_dn *samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
1433 {
1434         TALLOC_CTX *local_ctx;
1435         struct ldb_dn *sdn = dn;
1436         struct ldb_result *res = NULL;
1437         int ret = 0;
1438         const char *attrs[] = { NULL };
1439
1440         local_ctx = talloc_new(mem_ctx);
1441         if (local_ctx == NULL) return NULL;
1442         
1443         while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1444                 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE, 
1445                                  "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1446                 if (ret == LDB_SUCCESS) {
1447                         talloc_steal(local_ctx, res);
1448                         if (res->count == 1) {
1449                                 break;
1450                         }
1451                 }
1452         }
1453
1454         if (ret != LDB_SUCCESS || res->count != 1) {
1455                 talloc_free(local_ctx);
1456                 return NULL;
1457         }
1458
1459         talloc_steal(mem_ctx, sdn);
1460         talloc_free(local_ctx);
1461
1462         return sdn;
1463 }
1464
1465 /*
1466   check that a password is sufficiently complex
1467 */
1468 static BOOL samdb_password_complexity_ok(const char *pass)
1469 {
1470         return check_password_quality(pass);
1471 }
1472
1473
1474
1475 /*
1476   set the user password using plaintext, obeying any user or domain
1477   password restrictions
1478
1479   note that this function doesn't actually store the result in the
1480   database, it just fills in the "mod" structure with ldb modify
1481   elements to setup the correct change when samdb_replace() is
1482   called. This allows the caller to combine the change with other
1483   changes (as is needed by some of the set user info levels)
1484
1485   The caller should probably have a transaction wrapping this
1486 */
1487 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1488                             struct ldb_dn *user_dn,
1489                             struct ldb_dn *domain_dn,
1490                             struct ldb_message *mod,
1491                             const char *new_pass,
1492                             struct samr_Password *lmNewHash, 
1493                             struct samr_Password *ntNewHash,
1494                             BOOL user_change,
1495                             BOOL restrictions,
1496                             enum samr_RejectReason *reject_reason,
1497                             struct samr_DomInfo1 **_dominfo)
1498 {
1499         const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory", 
1500                                             "ntPwdHistory", 
1501                                             "dBCSPwd", "unicodePwd", 
1502                                             "objectSid", 
1503                                             "pwdLastSet", NULL };
1504         const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength", 
1505                                               "maxPwdAge", "minPwdAge", 
1506                                               "minPwdLength", NULL };
1507         NTTIME pwdLastSet;
1508         int64_t minPwdAge;
1509         uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1510         uint_t userAccountControl;
1511         struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1512         struct samr_Password local_lmNewHash, local_ntNewHash;
1513         int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1514         struct dom_sid *domain_sid;
1515         struct ldb_message **res;
1516         int count;
1517         time_t now = time(NULL);
1518         NTTIME now_nt;
1519         int i;
1520
1521         /* we need to know the time to compute password age */
1522         unix_to_nt_time(&now_nt, now);
1523
1524         /* pull all the user parameters */
1525         count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1526         if (count != 1) {
1527                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1528         }
1529         userAccountControl = samdb_result_uint(res[0],   "userAccountControl", 0);
1530         sambaLMPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1531                                                  "lmPwdHistory", &sambaLMPwdHistory);
1532         sambaNTPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1533                                                  "ntPwdHistory", &sambaNTPwdHistory);
1534         lmPwdHash =          samdb_result_hash(mem_ctx, res[0],   "dBCSPwd");
1535         ntPwdHash =          samdb_result_hash(mem_ctx, res[0],   "unicodePwd");
1536         pwdLastSet =         samdb_result_uint64(res[0], "pwdLastSet", 0);
1537
1538         if (domain_dn) {
1539                 /* pull the domain parameters */
1540                 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1541                 if (count != 1) {
1542                         DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n", 
1543                                   ldb_dn_get_linearized(domain_dn),
1544                                   ldb_dn_get_linearized(user_dn)));
1545                         return NT_STATUS_NO_SUCH_DOMAIN;
1546                 }
1547         } else {
1548                 /* work out the domain sid, and pull the domain from there */
1549                 domain_sid =         samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1550                 if (domain_sid == NULL) {
1551                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1552                 }
1553
1554                 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs, 
1555                                      "(objectSid=%s)", 
1556                                      ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1557                 if (count != 1) {
1558                         DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n", 
1559                                   dom_sid_string(mem_ctx, domain_sid),
1560                                   ldb_dn_get_linearized(user_dn)));
1561                         return NT_STATUS_NO_SUCH_DOMAIN;
1562                 }
1563         }
1564
1565         pwdProperties =    samdb_result_uint(res[0],   "pwdProperties", 0);
1566         pwdHistoryLength = samdb_result_uint(res[0],   "pwdHistoryLength", 0);
1567         minPwdLength =     samdb_result_uint(res[0],   "minPwdLength", 0);
1568         minPwdAge =        samdb_result_int64(res[0],  "minPwdAge", 0);
1569
1570         if (_dominfo) {
1571                 struct samr_DomInfo1 *dominfo;
1572                 /* on failure we need to fill in the reject reasons */
1573                 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1574                 if (dominfo == NULL) {
1575                         return NT_STATUS_NO_MEMORY;
1576                 }
1577                 dominfo->min_password_length     = minPwdLength;
1578                 dominfo->password_properties     = pwdProperties;
1579                 dominfo->password_history_length = pwdHistoryLength;
1580                 dominfo->max_password_age        = minPwdAge;
1581                 dominfo->min_password_age        = minPwdAge;
1582                 *_dominfo = dominfo;
1583         }
1584
1585         if (new_pass) {
1586                 /* check the various password restrictions */
1587                 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1588                         if (reject_reason) {
1589                                 *reject_reason = SAMR_REJECT_TOO_SHORT;
1590                         }
1591                         return NT_STATUS_PASSWORD_RESTRICTION;
1592                 }
1593                 
1594                 /* possibly check password complexity */
1595                 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1596                     !samdb_password_complexity_ok(new_pass)) {
1597                         if (reject_reason) {
1598                                 *reject_reason = SAMR_REJECT_COMPLEXITY;
1599                         }
1600                         return NT_STATUS_PASSWORD_RESTRICTION;
1601                 }
1602                 
1603                 /* compute the new nt and lm hashes */
1604                 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1605                         lmNewHash = &local_lmNewHash;
1606                 }
1607                 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1608                         /* If we can't convert this password to UCS2, then we should not accept it */
1609                         if (reject_reason) {
1610                                 *reject_reason = SAMR_REJECT_OTHER;
1611                         }
1612                         return NT_STATUS_PASSWORD_RESTRICTION;
1613                 }
1614                 ntNewHash = &local_ntNewHash;
1615         }
1616
1617         if (restrictions && user_change) {
1618                 /* are all password changes disallowed? */
1619                 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1620                         if (reject_reason) {
1621                                 *reject_reason = SAMR_REJECT_OTHER;
1622                         }
1623                         return NT_STATUS_PASSWORD_RESTRICTION;
1624                 }
1625                 
1626                 /* can this user change password? */
1627                 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1628                         if (reject_reason) {
1629                                 *reject_reason = SAMR_REJECT_OTHER;
1630                         }
1631                         return NT_STATUS_PASSWORD_RESTRICTION;
1632                 }
1633                 
1634                 /* yes, this is a minus. The ages are in negative 100nsec units! */
1635                 if (pwdLastSet - minPwdAge > now_nt) {
1636                         if (reject_reason) {
1637                                 *reject_reason = SAMR_REJECT_OTHER;
1638                         }
1639                         return NT_STATUS_PASSWORD_RESTRICTION;
1640                 }
1641
1642                 /* check the immediately past password */
1643                 if (pwdHistoryLength > 0) {
1644                         if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1645                                 if (reject_reason) {
1646                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1647                                 }
1648                                 return NT_STATUS_PASSWORD_RESTRICTION;
1649                         }
1650                         if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1651                                 if (reject_reason) {
1652                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1653                                 }
1654                                 return NT_STATUS_PASSWORD_RESTRICTION;
1655                         }
1656                 }
1657                 
1658                 /* check the password history */
1659                 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1660                 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1661                 
1662                 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1663                         if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1664                                 if (reject_reason) {
1665                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1666                                 }
1667                                 return NT_STATUS_PASSWORD_RESTRICTION;
1668                         }
1669                 }
1670                 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1671                         if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1672                                 if (reject_reason) {
1673                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1674                                 }
1675                                 return NT_STATUS_PASSWORD_RESTRICTION;
1676                         }
1677                 }
1678         }
1679
1680 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1681
1682         /* the password is acceptable. Start forming the new fields */
1683         if (new_pass) {
1684                 /* if we know the cleartext, then only set it.
1685                  * Modules in ldb will set all the appropriate
1686                  * hashes */
1687                 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod, 
1688                                                "sambaPassword", new_pass));
1689         } else {
1690                 /* We don't have the cleartext, so delete the old one
1691                  * and set what we have of the hashes */
1692                 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1693
1694                 if (lmNewHash) {
1695                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1696                 } else {
1697                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1698                 }
1699                 
1700                 if (ntNewHash) {
1701                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1702                 } else {
1703                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1704                 }
1705         }
1706
1707         return NT_STATUS_OK;
1708 }
1709
1710
1711 /*
1712   set the user password using plaintext, obeying any user or domain
1713   password restrictions
1714
1715   This wrapper function takes a SID as input, rather than a user DN,
1716   and actually performs the password change
1717
1718 */
1719 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1720                                 const struct dom_sid *user_sid,
1721                                 const char *new_pass,
1722                                 struct samr_Password *lmNewHash, 
1723                                 struct samr_Password *ntNewHash,
1724                                 BOOL user_change,
1725                                 BOOL restrictions,
1726                                 enum samr_RejectReason *reject_reason,
1727                                 struct samr_DomInfo1 **_dominfo) 
1728 {
1729         NTSTATUS nt_status;
1730         struct ldb_dn *user_dn;
1731         struct ldb_message *msg;
1732         int ret;
1733
1734         ret = ldb_transaction_start(ctx);
1735         if (ret) {
1736                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1737                 return NT_STATUS_TRANSACTION_ABORTED;
1738         }
1739
1740         user_dn = samdb_search_dn(ctx, mem_ctx, NULL, 
1741                                   "(&(objectSid=%s)(objectClass=user))", 
1742                                   ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1743         if (!user_dn) {
1744                 ldb_transaction_cancel(ctx);
1745                 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1746                           dom_sid_string(mem_ctx, user_sid)));
1747                 return NT_STATUS_NO_SUCH_USER;
1748         }
1749
1750         msg = ldb_msg_new(mem_ctx);
1751         if (msg == NULL) {
1752                 ldb_transaction_cancel(ctx);
1753                 return NT_STATUS_NO_MEMORY;
1754         }
1755
1756         msg->dn = ldb_dn_copy(msg, user_dn);
1757         if (!msg->dn) {
1758                 ldb_transaction_cancel(ctx);
1759                 return NT_STATUS_NO_MEMORY;
1760         }
1761
1762         nt_status = samdb_set_password(ctx, mem_ctx,
1763                                        user_dn, NULL,
1764                                        msg, new_pass, 
1765                                        lmNewHash, ntNewHash,
1766                                        user_change, /* This is a password set, not change */
1767                                        restrictions, /* run restriction tests */
1768                                        reject_reason, _dominfo);
1769         if (!NT_STATUS_IS_OK(nt_status)) {
1770                 ldb_transaction_cancel(ctx);
1771                 return nt_status;
1772         }
1773         
1774         /* modify the samdb record */
1775         ret = samdb_replace(ctx, mem_ctx, msg);
1776         if (ret != 0) {
1777                 ldb_transaction_cancel(ctx);
1778                 return NT_STATUS_ACCESS_DENIED;
1779         }
1780
1781         ret = ldb_transaction_commit(ctx);
1782         if (ret != 0) {
1783                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1784                          ldb_dn_get_linearized(msg->dn),
1785                          ldb_errstring(ctx)));
1786                 return NT_STATUS_TRANSACTION_ABORTED;
1787         }
1788         return NT_STATUS_OK;
1789 }
1790
1791 /****************************************************************************
1792  Create the SID list for this user.
1793 ****************************************************************************/
1794 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx, 
1795                                struct dom_sid *user_sid,
1796                                struct dom_sid *group_sid, 
1797                                int n_groupSIDs,
1798                                struct dom_sid **groupSIDs, 
1799                                BOOL is_authenticated,
1800                                struct security_token **token)
1801 {
1802         struct security_token *ptoken;
1803         int i;
1804         NTSTATUS status;
1805
1806         ptoken = security_token_initialise(mem_ctx);
1807         NT_STATUS_HAVE_NO_MEMORY(ptoken);
1808
1809         ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1810         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1811
1812         ptoken->user_sid = talloc_reference(ptoken, user_sid);
1813         ptoken->group_sid = talloc_reference(ptoken, group_sid);
1814         ptoken->privilege_mask = 0;
1815
1816         ptoken->sids[0] = ptoken->user_sid;
1817         ptoken->sids[1] = ptoken->group_sid;
1818
1819         /*
1820          * Finally add the "standard" SIDs.
1821          * The only difference between guest and "anonymous"
1822          * is the addition of Authenticated_Users.
1823          */
1824         ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1825         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1826         ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1827         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1828         ptoken->num_sids = 4;
1829
1830         if (is_authenticated) {
1831                 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1832                 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1833                 ptoken->num_sids++;
1834         }
1835
1836         for (i = 0; i < n_groupSIDs; i++) {
1837                 size_t check_sid_idx;
1838                 for (check_sid_idx = 1; 
1839                      check_sid_idx < ptoken->num_sids; 
1840                      check_sid_idx++) {
1841                         if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1842                                 break;
1843                         }
1844                 }
1845
1846                 if (check_sid_idx == ptoken->num_sids) {
1847                         ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1848                 }
1849         }
1850
1851         /* setup the privilege mask for this token */
1852         status = samdb_privilege_setup(ptoken);
1853         if (!NT_STATUS_IS_OK(status)) {
1854                 talloc_free(ptoken);
1855                 return status;
1856         }
1857
1858         security_token_debug(10, ptoken);
1859
1860         *token = ptoken;
1861
1862         return NT_STATUS_OK;
1863 }
1864
1865
1866 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
1867                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
1868 {
1869         struct ldb_message *msg;
1870         struct ldb_dn *basedn;
1871         const char *sidstr;
1872         int ret;
1873         
1874         sidstr = dom_sid_string(mem_ctx, sid);
1875         NT_STATUS_HAVE_NO_MEMORY(sidstr);
1876         
1877         /* We might have to create a ForeignSecurityPrincipal, even if this user
1878          * is in our own domain */
1879         
1880         msg = ldb_msg_new(mem_ctx);
1881         if (msg == NULL) {
1882                 return NT_STATUS_NO_MEMORY;
1883         }
1884         
1885         /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1886          * put the ForeignSecurityPrincipals? d_state->domain_dn does
1887          * not work, this is wrong for the Builtin domain, there's no
1888          * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
1889          */
1890         
1891         basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1892                                  "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1893         
1894         if (basedn == NULL) {
1895                 DEBUG(0, ("Failed to find DN for "
1896                           "ForeignSecurityPrincipal container\n"));
1897                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1898         }
1899         
1900         /* add core elements to the ldb_message for the alias */
1901         msg->dn = ldb_dn_copy(mem_ctx, basedn);
1902         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1903                 return NT_STATUS_NO_MEMORY;
1904         
1905         samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1906                              "objectClass",
1907                              "foreignSecurityPrincipal");
1908         
1909         /* create the alias */
1910         ret = samdb_add(sam_ctx, mem_ctx, msg);
1911         if (ret != 0) {
1912                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1913                          "record %s: %s\n", 
1914                          ldb_dn_get_linearized(msg->dn),
1915                          ldb_errstring(sam_ctx)));
1916                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1917         }
1918         *ret_dn = msg->dn;
1919         return NT_STATUS_OK;
1920 }
1921
1922
1923 /*
1924   Find the DN of a domain, assuming it to be a dotted.dns name
1925 */
1926
1927 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) 
1928 {
1929         int i;
1930         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1931         const char *binary_encoded;
1932         const char **split_realm;
1933         struct ldb_dn *dn;
1934         
1935         if (!tmp_ctx) {
1936                 return NULL;
1937         }
1938         
1939         split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1940         if (!split_realm) {
1941                 talloc_free(tmp_ctx);
1942                 return NULL;
1943         }
1944         dn = ldb_dn_new(mem_ctx, ldb, NULL);
1945         for (i=0; split_realm[i]; i++) {
1946                 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1947                 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1948                         DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1949                                   binary_encoded, ldb_dn_get_linearized(dn)));
1950                         talloc_free(tmp_ctx);
1951                         return NULL;
1952                 }
1953         }
1954         if (!ldb_dn_validate(dn)) {
1955                 DEBUG(2, ("Failed to validated DN %s\n",
1956                           ldb_dn_get_linearized(dn)));
1957                 return NULL;
1958         }
1959         return dn;
1960 }
1961 /*
1962   Find the DN of a domain, be it the netbios or DNS name 
1963 */
1964
1965 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
1966                                   const char *domain_name) 
1967 {
1968         const char * const domain_ref_attrs[] = {
1969                 "ncName", NULL
1970         };
1971         const char * const domain_ref2_attrs[] = {
1972                 NULL
1973         };
1974         struct ldb_result *res_domain_ref;
1975         char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1976         /* find the domain's DN */
1977         int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx, 
1978                                             &res_domain_ref, 
1979                                             samdb_partitions_dn(ldb, mem_ctx), 
1980                                             LDB_SCOPE_ONELEVEL, 
1981                                             domain_ref_attrs,
1982                                             "(&(nETBIOSName=%s)(objectclass=crossRef))", 
1983                                             escaped_domain);
1984         if (ret_domain != 0) {
1985                 return NULL;
1986         }
1987         
1988         if (res_domain_ref->count == 0) {
1989                 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx, 
1990                                                 &res_domain_ref, 
1991                                                 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
1992                                                 LDB_SCOPE_BASE,
1993                                                 domain_ref2_attrs,
1994                                                 "(objectclass=domain)");
1995                 if (ret_domain != 0) {
1996                         return NULL;
1997                 }
1998         
1999                 if (res_domain_ref->count == 1) {
2000                         return res_domain_ref->msgs[0]->dn;
2001                 }
2002                 return NULL;
2003         }
2004         
2005         if (res_domain_ref->count > 1) {
2006                 DEBUG(0,("Found %d records matching domain [%s]\n", 
2007                          ret_domain, domain_name));
2008                 return NULL;
2009         }
2010         
2011         return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2012
2013 }