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