r21503: add usefull function to get the site dn for the local server
[kai/samba-autobuild/.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 the server dn for the current open ldb
1388 */
1389 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1390 {
1391         struct ldb_dn *server_dn;
1392         struct ldb_dn *server_site_dn;
1393
1394         server_dn = samdb_server_dn(ldb, mem_ctx);
1395         if (!server_dn) return NULL;
1396
1397         server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1398
1399         talloc_free(server_dn);
1400         return server_site_dn;
1401 }
1402
1403 /*
1404   work out if we are the PDC for the domain of the current open ldb
1405 */
1406 BOOL samdb_is_pdc(struct ldb_context *ldb)
1407 {
1408         const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1409         int ret;
1410         struct ldb_result *dom_res;
1411         TALLOC_CTX *tmp_ctx;
1412         BOOL is_pdc;
1413         struct ldb_dn *pdc;
1414
1415         tmp_ctx = talloc_new(ldb);
1416         if (tmp_ctx == NULL) {
1417                 goto failed;
1418         }
1419
1420         ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1421         if (ret) {
1422                 goto failed;
1423         }
1424         talloc_steal(tmp_ctx, dom_res);
1425         if (dom_res->count != 1) {
1426                 goto failed;
1427         }
1428
1429         pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1430
1431         if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1432                 is_pdc = True;
1433         } else {
1434                 is_pdc = False;
1435         }
1436
1437         talloc_free(tmp_ctx);
1438
1439         return is_pdc;
1440
1441 failed:
1442         DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1443         talloc_free(tmp_ctx);
1444         return False;
1445 }
1446
1447
1448 /* Find a domain object in the parents of a particular DN.  */
1449 struct ldb_dn *samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
1450 {
1451         TALLOC_CTX *local_ctx;
1452         struct ldb_dn *sdn = dn;
1453         struct ldb_result *res = NULL;
1454         int ret = 0;
1455         const char *attrs[] = { NULL };
1456
1457         local_ctx = talloc_new(mem_ctx);
1458         if (local_ctx == NULL) return NULL;
1459         
1460         while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1461                 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE, 
1462                                  "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1463                 if (ret == LDB_SUCCESS) {
1464                         talloc_steal(local_ctx, res);
1465                         if (res->count == 1) {
1466                                 break;
1467                         }
1468                 }
1469         }
1470
1471         if (ret != LDB_SUCCESS || res->count != 1) {
1472                 talloc_free(local_ctx);
1473                 return NULL;
1474         }
1475
1476         talloc_steal(mem_ctx, sdn);
1477         talloc_free(local_ctx);
1478
1479         return sdn;
1480 }
1481
1482 /*
1483   check that a password is sufficiently complex
1484 */
1485 static BOOL samdb_password_complexity_ok(const char *pass)
1486 {
1487         return check_password_quality(pass);
1488 }
1489
1490
1491
1492 /*
1493   set the user password using plaintext, obeying any user or domain
1494   password restrictions
1495
1496   note that this function doesn't actually store the result in the
1497   database, it just fills in the "mod" structure with ldb modify
1498   elements to setup the correct change when samdb_replace() is
1499   called. This allows the caller to combine the change with other
1500   changes (as is needed by some of the set user info levels)
1501
1502   The caller should probably have a transaction wrapping this
1503 */
1504 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1505                             struct ldb_dn *user_dn,
1506                             struct ldb_dn *domain_dn,
1507                             struct ldb_message *mod,
1508                             const char *new_pass,
1509                             struct samr_Password *lmNewHash, 
1510                             struct samr_Password *ntNewHash,
1511                             BOOL user_change,
1512                             BOOL restrictions,
1513                             enum samr_RejectReason *reject_reason,
1514                             struct samr_DomInfo1 **_dominfo)
1515 {
1516         const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory", 
1517                                             "ntPwdHistory", 
1518                                             "dBCSPwd", "unicodePwd", 
1519                                             "objectSid", 
1520                                             "pwdLastSet", NULL };
1521         const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength", 
1522                                               "maxPwdAge", "minPwdAge", 
1523                                               "minPwdLength", NULL };
1524         NTTIME pwdLastSet;
1525         int64_t minPwdAge;
1526         uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1527         uint_t userAccountControl;
1528         struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1529         struct samr_Password local_lmNewHash, local_ntNewHash;
1530         int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1531         struct dom_sid *domain_sid;
1532         struct ldb_message **res;
1533         int count;
1534         time_t now = time(NULL);
1535         NTTIME now_nt;
1536         int i;
1537
1538         /* we need to know the time to compute password age */
1539         unix_to_nt_time(&now_nt, now);
1540
1541         /* pull all the user parameters */
1542         count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1543         if (count != 1) {
1544                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1545         }
1546         userAccountControl = samdb_result_uint(res[0],   "userAccountControl", 0);
1547         sambaLMPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1548                                                  "lmPwdHistory", &sambaLMPwdHistory);
1549         sambaNTPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1550                                                  "ntPwdHistory", &sambaNTPwdHistory);
1551         lmPwdHash =          samdb_result_hash(mem_ctx, res[0],   "dBCSPwd");
1552         ntPwdHash =          samdb_result_hash(mem_ctx, res[0],   "unicodePwd");
1553         pwdLastSet =         samdb_result_uint64(res[0], "pwdLastSet", 0);
1554
1555         if (domain_dn) {
1556                 /* pull the domain parameters */
1557                 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1558                 if (count != 1) {
1559                         DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n", 
1560                                   ldb_dn_get_linearized(domain_dn),
1561                                   ldb_dn_get_linearized(user_dn)));
1562                         return NT_STATUS_NO_SUCH_DOMAIN;
1563                 }
1564         } else {
1565                 /* work out the domain sid, and pull the domain from there */
1566                 domain_sid =         samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1567                 if (domain_sid == NULL) {
1568                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1569                 }
1570
1571                 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs, 
1572                                      "(objectSid=%s)", 
1573                                      ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1574                 if (count != 1) {
1575                         DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n", 
1576                                   dom_sid_string(mem_ctx, domain_sid),
1577                                   ldb_dn_get_linearized(user_dn)));
1578                         return NT_STATUS_NO_SUCH_DOMAIN;
1579                 }
1580         }
1581
1582         pwdProperties =    samdb_result_uint(res[0],   "pwdProperties", 0);
1583         pwdHistoryLength = samdb_result_uint(res[0],   "pwdHistoryLength", 0);
1584         minPwdLength =     samdb_result_uint(res[0],   "minPwdLength", 0);
1585         minPwdAge =        samdb_result_int64(res[0],  "minPwdAge", 0);
1586
1587         if (_dominfo) {
1588                 struct samr_DomInfo1 *dominfo;
1589                 /* on failure we need to fill in the reject reasons */
1590                 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1591                 if (dominfo == NULL) {
1592                         return NT_STATUS_NO_MEMORY;
1593                 }
1594                 dominfo->min_password_length     = minPwdLength;
1595                 dominfo->password_properties     = pwdProperties;
1596                 dominfo->password_history_length = pwdHistoryLength;
1597                 dominfo->max_password_age        = minPwdAge;
1598                 dominfo->min_password_age        = minPwdAge;
1599                 *_dominfo = dominfo;
1600         }
1601
1602         if (new_pass) {
1603                 /* check the various password restrictions */
1604                 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1605                         if (reject_reason) {
1606                                 *reject_reason = SAMR_REJECT_TOO_SHORT;
1607                         }
1608                         return NT_STATUS_PASSWORD_RESTRICTION;
1609                 }
1610                 
1611                 /* possibly check password complexity */
1612                 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1613                     !samdb_password_complexity_ok(new_pass)) {
1614                         if (reject_reason) {
1615                                 *reject_reason = SAMR_REJECT_COMPLEXITY;
1616                         }
1617                         return NT_STATUS_PASSWORD_RESTRICTION;
1618                 }
1619                 
1620                 /* compute the new nt and lm hashes */
1621                 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1622                         lmNewHash = &local_lmNewHash;
1623                 }
1624                 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1625                         /* If we can't convert this password to UCS2, then we should not accept it */
1626                         if (reject_reason) {
1627                                 *reject_reason = SAMR_REJECT_OTHER;
1628                         }
1629                         return NT_STATUS_PASSWORD_RESTRICTION;
1630                 }
1631                 ntNewHash = &local_ntNewHash;
1632         }
1633
1634         if (restrictions && user_change) {
1635                 /* are all password changes disallowed? */
1636                 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1637                         if (reject_reason) {
1638                                 *reject_reason = SAMR_REJECT_OTHER;
1639                         }
1640                         return NT_STATUS_PASSWORD_RESTRICTION;
1641                 }
1642                 
1643                 /* can this user change password? */
1644                 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1645                         if (reject_reason) {
1646                                 *reject_reason = SAMR_REJECT_OTHER;
1647                         }
1648                         return NT_STATUS_PASSWORD_RESTRICTION;
1649                 }
1650                 
1651                 /* yes, this is a minus. The ages are in negative 100nsec units! */
1652                 if (pwdLastSet - minPwdAge > now_nt) {
1653                         if (reject_reason) {
1654                                 *reject_reason = SAMR_REJECT_OTHER;
1655                         }
1656                         return NT_STATUS_PASSWORD_RESTRICTION;
1657                 }
1658
1659                 /* check the immediately past password */
1660                 if (pwdHistoryLength > 0) {
1661                         if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1662                                 if (reject_reason) {
1663                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1664                                 }
1665                                 return NT_STATUS_PASSWORD_RESTRICTION;
1666                         }
1667                         if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1668                                 if (reject_reason) {
1669                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1670                                 }
1671                                 return NT_STATUS_PASSWORD_RESTRICTION;
1672                         }
1673                 }
1674                 
1675                 /* check the password history */
1676                 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1677                 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1678                 
1679                 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1680                         if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1681                                 if (reject_reason) {
1682                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1683                                 }
1684                                 return NT_STATUS_PASSWORD_RESTRICTION;
1685                         }
1686                 }
1687                 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1688                         if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1689                                 if (reject_reason) {
1690                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1691                                 }
1692                                 return NT_STATUS_PASSWORD_RESTRICTION;
1693                         }
1694                 }
1695         }
1696
1697 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1698
1699         /* the password is acceptable. Start forming the new fields */
1700         if (new_pass) {
1701                 /* if we know the cleartext, then only set it.
1702                  * Modules in ldb will set all the appropriate
1703                  * hashes */
1704                 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod, 
1705                                                "sambaPassword", new_pass));
1706         } else {
1707                 /* We don't have the cleartext, so delete the old one
1708                  * and set what we have of the hashes */
1709                 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1710
1711                 if (lmNewHash) {
1712                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1713                 } else {
1714                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1715                 }
1716                 
1717                 if (ntNewHash) {
1718                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1719                 } else {
1720                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1721                 }
1722         }
1723
1724         return NT_STATUS_OK;
1725 }
1726
1727
1728 /*
1729   set the user password using plaintext, obeying any user or domain
1730   password restrictions
1731
1732   This wrapper function takes a SID as input, rather than a user DN,
1733   and actually performs the password change
1734
1735 */
1736 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1737                                 const struct dom_sid *user_sid,
1738                                 const char *new_pass,
1739                                 struct samr_Password *lmNewHash, 
1740                                 struct samr_Password *ntNewHash,
1741                                 BOOL user_change,
1742                                 BOOL restrictions,
1743                                 enum samr_RejectReason *reject_reason,
1744                                 struct samr_DomInfo1 **_dominfo) 
1745 {
1746         NTSTATUS nt_status;
1747         struct ldb_dn *user_dn;
1748         struct ldb_message *msg;
1749         int ret;
1750
1751         ret = ldb_transaction_start(ctx);
1752         if (ret) {
1753                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1754                 return NT_STATUS_TRANSACTION_ABORTED;
1755         }
1756
1757         user_dn = samdb_search_dn(ctx, mem_ctx, NULL, 
1758                                   "(&(objectSid=%s)(objectClass=user))", 
1759                                   ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1760         if (!user_dn) {
1761                 ldb_transaction_cancel(ctx);
1762                 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1763                           dom_sid_string(mem_ctx, user_sid)));
1764                 return NT_STATUS_NO_SUCH_USER;
1765         }
1766
1767         msg = ldb_msg_new(mem_ctx);
1768         if (msg == NULL) {
1769                 ldb_transaction_cancel(ctx);
1770                 return NT_STATUS_NO_MEMORY;
1771         }
1772
1773         msg->dn = ldb_dn_copy(msg, user_dn);
1774         if (!msg->dn) {
1775                 ldb_transaction_cancel(ctx);
1776                 return NT_STATUS_NO_MEMORY;
1777         }
1778
1779         nt_status = samdb_set_password(ctx, mem_ctx,
1780                                        user_dn, NULL,
1781                                        msg, new_pass, 
1782                                        lmNewHash, ntNewHash,
1783                                        user_change, /* This is a password set, not change */
1784                                        restrictions, /* run restriction tests */
1785                                        reject_reason, _dominfo);
1786         if (!NT_STATUS_IS_OK(nt_status)) {
1787                 ldb_transaction_cancel(ctx);
1788                 return nt_status;
1789         }
1790         
1791         /* modify the samdb record */
1792         ret = samdb_replace(ctx, mem_ctx, msg);
1793         if (ret != 0) {
1794                 ldb_transaction_cancel(ctx);
1795                 return NT_STATUS_ACCESS_DENIED;
1796         }
1797
1798         ret = ldb_transaction_commit(ctx);
1799         if (ret != 0) {
1800                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1801                          ldb_dn_get_linearized(msg->dn),
1802                          ldb_errstring(ctx)));
1803                 return NT_STATUS_TRANSACTION_ABORTED;
1804         }
1805         return NT_STATUS_OK;
1806 }
1807
1808 /****************************************************************************
1809  Create the SID list for this user.
1810 ****************************************************************************/
1811 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx, 
1812                                struct dom_sid *user_sid,
1813                                struct dom_sid *group_sid, 
1814                                int n_groupSIDs,
1815                                struct dom_sid **groupSIDs, 
1816                                BOOL is_authenticated,
1817                                struct security_token **token)
1818 {
1819         struct security_token *ptoken;
1820         int i;
1821         NTSTATUS status;
1822
1823         ptoken = security_token_initialise(mem_ctx);
1824         NT_STATUS_HAVE_NO_MEMORY(ptoken);
1825
1826         ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1827         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1828
1829         ptoken->user_sid = talloc_reference(ptoken, user_sid);
1830         ptoken->group_sid = talloc_reference(ptoken, group_sid);
1831         ptoken->privilege_mask = 0;
1832
1833         ptoken->sids[0] = ptoken->user_sid;
1834         ptoken->sids[1] = ptoken->group_sid;
1835
1836         /*
1837          * Finally add the "standard" SIDs.
1838          * The only difference between guest and "anonymous"
1839          * is the addition of Authenticated_Users.
1840          */
1841         ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1842         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1843         ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1844         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1845         ptoken->num_sids = 4;
1846
1847         if (is_authenticated) {
1848                 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1849                 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1850                 ptoken->num_sids++;
1851         }
1852
1853         for (i = 0; i < n_groupSIDs; i++) {
1854                 size_t check_sid_idx;
1855                 for (check_sid_idx = 1; 
1856                      check_sid_idx < ptoken->num_sids; 
1857                      check_sid_idx++) {
1858                         if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1859                                 break;
1860                         }
1861                 }
1862
1863                 if (check_sid_idx == ptoken->num_sids) {
1864                         ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1865                 }
1866         }
1867
1868         /* setup the privilege mask for this token */
1869         status = samdb_privilege_setup(ptoken);
1870         if (!NT_STATUS_IS_OK(status)) {
1871                 talloc_free(ptoken);
1872                 return status;
1873         }
1874
1875         security_token_debug(10, ptoken);
1876
1877         *token = ptoken;
1878
1879         return NT_STATUS_OK;
1880 }
1881
1882
1883 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
1884                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
1885 {
1886         struct ldb_message *msg;
1887         struct ldb_dn *basedn;
1888         const char *sidstr;
1889         int ret;
1890         
1891         sidstr = dom_sid_string(mem_ctx, sid);
1892         NT_STATUS_HAVE_NO_MEMORY(sidstr);
1893         
1894         /* We might have to create a ForeignSecurityPrincipal, even if this user
1895          * is in our own domain */
1896         
1897         msg = ldb_msg_new(mem_ctx);
1898         if (msg == NULL) {
1899                 return NT_STATUS_NO_MEMORY;
1900         }
1901         
1902         /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1903          * put the ForeignSecurityPrincipals? d_state->domain_dn does
1904          * not work, this is wrong for the Builtin domain, there's no
1905          * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
1906          */
1907         
1908         basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1909                                  "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1910         
1911         if (basedn == NULL) {
1912                 DEBUG(0, ("Failed to find DN for "
1913                           "ForeignSecurityPrincipal container\n"));
1914                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1915         }
1916         
1917         /* add core elements to the ldb_message for the alias */
1918         msg->dn = ldb_dn_copy(mem_ctx, basedn);
1919         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1920                 return NT_STATUS_NO_MEMORY;
1921         
1922         samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1923                              "objectClass",
1924                              "foreignSecurityPrincipal");
1925         
1926         /* create the alias */
1927         ret = samdb_add(sam_ctx, mem_ctx, msg);
1928         if (ret != 0) {
1929                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1930                          "record %s: %s\n", 
1931                          ldb_dn_get_linearized(msg->dn),
1932                          ldb_errstring(sam_ctx)));
1933                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1934         }
1935         *ret_dn = msg->dn;
1936         return NT_STATUS_OK;
1937 }
1938
1939
1940 /*
1941   Find the DN of a domain, assuming it to be a dotted.dns name
1942 */
1943
1944 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) 
1945 {
1946         int i;
1947         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1948         const char *binary_encoded;
1949         const char **split_realm;
1950         struct ldb_dn *dn;
1951         
1952         if (!tmp_ctx) {
1953                 return NULL;
1954         }
1955         
1956         split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1957         if (!split_realm) {
1958                 talloc_free(tmp_ctx);
1959                 return NULL;
1960         }
1961         dn = ldb_dn_new(mem_ctx, ldb, NULL);
1962         for (i=0; split_realm[i]; i++) {
1963                 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1964                 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1965                         DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1966                                   binary_encoded, ldb_dn_get_linearized(dn)));
1967                         talloc_free(tmp_ctx);
1968                         return NULL;
1969                 }
1970         }
1971         if (!ldb_dn_validate(dn)) {
1972                 DEBUG(2, ("Failed to validated DN %s\n",
1973                           ldb_dn_get_linearized(dn)));
1974                 return NULL;
1975         }
1976         return dn;
1977 }
1978 /*
1979   Find the DN of a domain, be it the netbios or DNS name 
1980 */
1981
1982 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
1983                                   const char *domain_name) 
1984 {
1985         const char * const domain_ref_attrs[] = {
1986                 "ncName", NULL
1987         };
1988         const char * const domain_ref2_attrs[] = {
1989                 NULL
1990         };
1991         struct ldb_result *res_domain_ref;
1992         char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1993         /* find the domain's DN */
1994         int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx, 
1995                                             &res_domain_ref, 
1996                                             samdb_partitions_dn(ldb, mem_ctx), 
1997                                             LDB_SCOPE_ONELEVEL, 
1998                                             domain_ref_attrs,
1999                                             "(&(nETBIOSName=%s)(objectclass=crossRef))", 
2000                                             escaped_domain);
2001         if (ret_domain != 0) {
2002                 return NULL;
2003         }
2004         
2005         if (res_domain_ref->count == 0) {
2006                 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx, 
2007                                                 &res_domain_ref, 
2008                                                 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2009                                                 LDB_SCOPE_BASE,
2010                                                 domain_ref2_attrs,
2011                                                 "(objectclass=domain)");
2012                 if (ret_domain != 0) {
2013                         return NULL;
2014                 }
2015         
2016                 if (res_domain_ref->count == 1) {
2017                         return res_domain_ref->msgs[0]->dn;
2018                 }
2019                 return NULL;
2020         }
2021         
2022         if (res_domain_ref->count > 1) {
2023                 DEBUG(0,("Found %d records matching domain [%s]\n", 
2024                          ret_domain, domain_name));
2025                 return NULL;
2026         }
2027         
2028         return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2029
2030 }