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