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