r24941: Simplify samdb_result_nttime(), and remove nttime_from_string()
[kai/samba.git] / source4 / dsdb / samdb / samdb.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    interface functions for the sam database
5
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Volker Lendecke 2004
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "librpc/gen_ndr/ndr_netlogon.h"
26 #include "librpc/gen_ndr/ndr_misc.h"
27 #include "librpc/gen_ndr/ndr_security.h"
28 #include "lib/ldb/include/ldb.h"
29 #include "lib/ldb/include/ldb_errors.h"
30 #include "libcli/security/security.h"
31 #include "libcli/auth/libcli_auth.h"
32 #include "libcli/ldap/ldap.h"
33 #include "system/time.h"
34 #include "system/filesys.h"
35 #include "db_wrap.h"
36 #include "dsdb/samdb/samdb.h"
37 #include "dsdb/common/flags.h"
38
39 /*
40   connect to the SAM database
41   return an opaque context pointer on success, or NULL on failure
42  */
43 struct ldb_context *samdb_connect(TALLOC_CTX *mem_ctx, 
44                                   struct auth_session_info *session_info)
45 {
46         struct ldb_context *ldb;
47         ldb = ldb_wrap_connect(mem_ctx, lp_sam_url(), session_info,
48                                NULL, 0, NULL);
49         if (!ldb) {
50                 return NULL;
51         }
52         dsdb_make_schema_global(ldb);
53         return ldb;
54 }
55
56 /*
57   search the sam for the specified attributes in a specific domain, filter on
58   objectSid being in domain_sid.
59 */
60 int samdb_search_domain(struct ldb_context *sam_ldb,
61                         TALLOC_CTX *mem_ctx, 
62                         struct ldb_dn *basedn,
63                         struct ldb_message ***res,
64                         const char * const *attrs,
65                         const struct dom_sid *domain_sid,
66                         const char *format, ...)  _PRINTF_ATTRIBUTE(7,8)
67 {
68         va_list ap;
69         int i, count;
70
71         va_start(ap, format);
72         count = gendb_search_v(sam_ldb, mem_ctx, basedn,
73                                res, attrs, format, ap);
74         va_end(ap);
75
76         i=0;
77
78         while (i<count) {
79                 struct dom_sid *entry_sid;
80
81                 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
82
83                 if ((entry_sid == NULL) ||
84                     (!dom_sid_in_domain(domain_sid, entry_sid))) {
85                         /* Delete that entry from the result set */
86                         (*res)[i] = (*res)[count-1];
87                         count -= 1;
88                         talloc_free(entry_sid);
89                         continue;
90                 }
91                 talloc_free(entry_sid);
92                 i += 1;
93         }
94
95         return count;
96 }
97
98 /*
99   search the sam for a single string attribute in exactly 1 record
100 */
101 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
102                                   TALLOC_CTX *mem_ctx,
103                                   struct ldb_dn *basedn,
104                                   const char *attr_name,
105                                   const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
106 {
107         int count;
108         const char *attrs[2] = { NULL, NULL };
109         struct ldb_message **res = NULL;
110
111         attrs[0] = attr_name;
112
113         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
114         if (count > 1) {                
115                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
116                          attr_name, format, count));
117         }
118         if (count != 1) {
119                 talloc_free(res);
120                 return NULL;
121         }
122
123         return samdb_result_string(res[0], attr_name, NULL);
124 }
125                                  
126
127 /*
128   search the sam for a single string attribute in exactly 1 record
129 */
130 const char *samdb_search_string(struct ldb_context *sam_ldb,
131                                 TALLOC_CTX *mem_ctx,
132                                 struct ldb_dn *basedn,
133                                 const char *attr_name,
134                                 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
135 {
136         va_list ap;
137         const char *str;
138
139         va_start(ap, format);
140         str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
141         va_end(ap);
142
143         return str;
144 }
145
146 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
147                                TALLOC_CTX *mem_ctx,
148                                struct ldb_dn *basedn,
149                                const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
150 {
151         va_list ap;
152         struct ldb_dn *ret;
153         struct ldb_message **res = NULL;
154         int count;
155
156         va_start(ap, format);
157         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
158         va_end(ap);
159
160         if (count != 1) return NULL;
161
162         ret = talloc_steal(mem_ctx, res[0]->dn);
163         talloc_free(res);
164
165         return ret;
166 }
167
168 /*
169   search the sam for a dom_sid attribute in exactly 1 record
170 */
171 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
172                                      TALLOC_CTX *mem_ctx,
173                                      struct ldb_dn *basedn,
174                                      const char *attr_name,
175                                      const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
176 {
177         va_list ap;
178         int count;
179         struct ldb_message **res;
180         const char *attrs[2] = { NULL, NULL };
181         struct dom_sid *sid;
182
183         attrs[0] = attr_name;
184
185         va_start(ap, format);
186         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
187         va_end(ap);
188         if (count > 1) {                
189                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
190                          attr_name, format, count));
191         }
192         if (count != 1) {
193                 talloc_free(res);
194                 return NULL;
195         }
196         sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
197         talloc_free(res);
198         return sid;     
199 }
200
201 /*
202   return the count of the number of records in the sam matching the query
203 */
204 int samdb_search_count(struct ldb_context *sam_ldb,
205                        TALLOC_CTX *mem_ctx,
206                        struct ldb_dn *basedn,
207                        const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
208 {
209         va_list ap;
210         struct ldb_message **res;
211         const char * const attrs[] = { NULL };
212         int ret;
213
214         va_start(ap, format);
215         ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
216         va_end(ap);
217
218         return ret;
219 }
220
221
222 /*
223   search the sam for a single integer attribute in exactly 1 record
224 */
225 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
226                          TALLOC_CTX *mem_ctx,
227                          uint_t default_value,
228                          struct ldb_dn *basedn,
229                          const char *attr_name,
230                          const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
231 {
232         va_list ap;
233         int count;
234         struct ldb_message **res;
235         const char *attrs[2] = { NULL, NULL };
236
237         attrs[0] = attr_name;
238
239         va_start(ap, format);
240         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
241         va_end(ap);
242
243         if (count != 1) {
244                 return default_value;
245         }
246
247         return samdb_result_uint(res[0], attr_name, default_value);
248 }
249
250 /*
251   search the sam for a single signed 64 bit integer attribute in exactly 1 record
252 */
253 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
254                            TALLOC_CTX *mem_ctx,
255                            int64_t default_value,
256                            struct ldb_dn *basedn,
257                            const char *attr_name,
258                            const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
259 {
260         va_list ap;
261         int count;
262         struct ldb_message **res;
263         const char *attrs[2] = { NULL, NULL };
264
265         attrs[0] = attr_name;
266
267         va_start(ap, format);
268         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
269         va_end(ap);
270
271         if (count != 1) {
272                 return default_value;
273         }
274
275         return samdb_result_int64(res[0], attr_name, default_value);
276 }
277
278 /*
279   search the sam for multipe records each giving a single string attribute
280   return the number of matches, or -1 on error
281 */
282 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
283                                  TALLOC_CTX *mem_ctx,
284                                  struct ldb_dn *basedn,
285                                  const char ***strs,
286                                  const char *attr_name,
287                                  const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
288 {
289         va_list ap;
290         int count, i;
291         const char *attrs[2] = { NULL, NULL };
292         struct ldb_message **res = NULL;
293
294         attrs[0] = attr_name;
295
296         va_start(ap, format);
297         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
298         va_end(ap);
299
300         if (count <= 0) {
301                 return count;
302         }
303
304         /* make sure its single valued */
305         for (i=0;i<count;i++) {
306                 if (res[i]->num_elements != 1) {
307                         DEBUG(1,("samdb: search for %s %s not single valued\n", 
308                                  attr_name, format));
309                         talloc_free(res);
310                         return -1;
311                 }
312         }
313
314         *strs = talloc_array(mem_ctx, const char *, count+1);
315         if (! *strs) {
316                 talloc_free(res);
317                 return -1;
318         }
319
320         for (i=0;i<count;i++) {
321                 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
322         }
323         (*strs)[count] = NULL;
324
325         return count;
326 }
327
328 /*
329   pull a uint from a result set. 
330 */
331 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
332 {
333         return ldb_msg_find_attr_as_uint(msg, attr, default_value);
334 }
335
336 /*
337   pull a (signed) int64 from a result set. 
338 */
339 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
340 {
341         return ldb_msg_find_attr_as_int64(msg, attr, default_value);
342 }
343
344 /*
345   pull a string from a result set. 
346 */
347 const char *samdb_result_string(const struct ldb_message *msg, const char *attr, 
348                                 const char *default_value)
349 {
350         return ldb_msg_find_attr_as_string(msg, attr, default_value);
351 }
352
353 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
354                                const char *attr, struct ldb_dn *default_value)
355 {
356         struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
357         if (!ret_dn) {
358                 return default_value;
359         }
360         return ret_dn;
361 }
362
363 /*
364   pull a rid from a objectSid in a result set. 
365 */
366 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
367                                    const char *attr, uint32_t default_value)
368 {
369         struct dom_sid *sid;
370         uint32_t rid;
371
372         sid = samdb_result_dom_sid(mem_ctx, msg, attr);
373         if (sid == NULL) {
374                 return default_value;
375         }
376         rid = sid->sub_auths[sid->num_auths-1];
377         talloc_free(sid);
378         return rid;
379 }
380
381 /*
382   pull a dom_sid structure from a objectSid in a result set. 
383 */
384 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
385                                      const char *attr)
386 {
387         const struct ldb_val *v;
388         struct dom_sid *sid;
389         NTSTATUS status;
390         v = ldb_msg_find_ldb_val(msg, attr);
391         if (v == NULL) {
392                 return NULL;
393         }
394         sid = talloc(mem_ctx, struct dom_sid);
395         if (sid == NULL) {
396                 return NULL;
397         }
398         status = ndr_pull_struct_blob(v, sid, sid, 
399                                       (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
400         if (!NT_STATUS_IS_OK(status)) {
401                 talloc_free(sid);
402                 return NULL;
403         }
404         return sid;
405 }
406
407 /*
408   pull a guid structure from a objectGUID in a result set. 
409 */
410 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
411 {
412         const struct ldb_val *v;
413         NTSTATUS status;
414         struct GUID guid;
415         TALLOC_CTX *mem_ctx;
416
417         ZERO_STRUCT(guid);
418
419         v = ldb_msg_find_ldb_val(msg, attr);
420         if (!v) return guid;
421
422         mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
423         if (!mem_ctx) return guid;
424         status = ndr_pull_struct_blob(v, mem_ctx, &guid, 
425                                       (ndr_pull_flags_fn_t)ndr_pull_GUID);
426         talloc_free(mem_ctx);
427         if (!NT_STATUS_IS_OK(status)) {
428                 return guid;
429         }
430
431         return guid;
432 }
433
434 /*
435   pull a sid prefix from a objectSid in a result set. 
436   this is used to find the domain sid for a user
437 */
438 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
439                                         const char *attr)
440 {
441         struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
442         if (!sid || sid->num_auths < 1) return NULL;
443         sid->num_auths--;
444         return sid;
445 }
446
447 /*
448   pull a NTTIME in a result set. 
449 */
450 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
451 {
452         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
453 }
454
455 /*
456   pull a uint64_t from a result set. 
457 */
458 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
459 {
460         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
461 }
462
463
464 /*
465   construct the allow_password_change field from the PwdLastSet attribute and the 
466   domain password settings
467 */
468 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb, 
469                                           TALLOC_CTX *mem_ctx, 
470                                           struct ldb_dn *domain_dn, 
471                                           struct ldb_message *msg, 
472                                           const char *attr)
473 {
474         uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
475         int64_t minPwdAge;
476
477         if (attr_time == 0) {
478                 return 0;
479         }
480
481         minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
482
483         /* yes, this is a -= not a += as minPwdAge is stored as the negative
484            of the number of 100-nano-seconds */
485         attr_time -= minPwdAge;
486
487         return attr_time;
488 }
489
490 /*
491   construct the force_password_change field from the PwdLastSet attribute and the 
492   domain password settings
493 */
494 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb, 
495                                           TALLOC_CTX *mem_ctx, 
496                                           struct ldb_dn *domain_dn, 
497                                           struct ldb_message *msg)
498 {
499         uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
500         uint32_t user_flags = samdb_result_uint64(msg, "userAccountControl", 0);
501         int64_t maxPwdAge;
502
503         if (user_flags & UF_DONT_EXPIRE_PASSWD) {
504                 return 0x7FFFFFFFFFFFFFFFULL;
505         }
506
507         if (attr_time == 0) {
508                 return 0;
509         }
510
511         maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
512         if (maxPwdAge == 0) {
513                 return 0;
514         } else {
515                 attr_time -= maxPwdAge;
516         }
517
518         return attr_time;
519 }
520
521 /*
522   pull a samr_Password structutre from a result set. 
523 */
524 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
525 {
526         struct samr_Password *hash = NULL;
527         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
528         if (val && (val->length >= sizeof(hash->hash))) {
529                 hash = talloc(mem_ctx, struct samr_Password);
530                 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
531         }
532         return hash;
533 }
534
535 /*
536   pull an array of samr_Password structutres from a result set. 
537 */
538 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
539                            const char *attr, struct samr_Password **hashes)
540 {
541         uint_t count = 0;
542         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
543         int i;
544
545         *hashes = NULL;
546         if (!val) {
547                 return 0;
548         }
549         count = val->length / 16;
550         if (count == 0) {
551                 return 0;
552         }
553
554         *hashes = talloc_array(mem_ctx, struct samr_Password, count);
555         if (! *hashes) {
556                 return 0;
557         }
558
559         for (i=0;i<count;i++) {
560                 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
561         }
562
563         return count;
564 }
565
566 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
567                                 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd) 
568 {
569         struct samr_Password *lmPwdHash, *ntPwdHash;
570         if (nt_pwd) {
571                 int num_nt;
572                 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
573                 if (num_nt == 0) {
574                         *nt_pwd = NULL;
575                 } else if (num_nt > 1) {
576                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
577                 } else {
578                         *nt_pwd = &ntPwdHash[0];
579                 }
580         }
581         if (lm_pwd) {
582                 int num_lm;
583                 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
584                 if (num_lm == 0) {
585                         *lm_pwd = NULL;
586                 } else if (num_lm > 1) {
587                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
588                 } else {
589                         *lm_pwd = &lmPwdHash[0];
590                 }
591         }
592         return NT_STATUS_OK;
593 }
594
595 /*
596   pull a samr_LogonHours structutre from a result set. 
597 */
598 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
599 {
600         struct samr_LogonHours hours;
601         const int units_per_week = 168;
602         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
603         ZERO_STRUCT(hours);
604         hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
605         if (!hours.bits) {
606                 return hours;
607         }
608         hours.units_per_week = units_per_week;
609         memset(hours.bits, 0xFF, units_per_week);
610         if (val) {
611                 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
612         }
613         return hours;
614 }
615
616 /*
617   pull a set of account_flags from a result set. 
618 */
619 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
620 {
621         uint_t userAccountControl = ldb_msg_find_attr_as_uint(msg, attr, 0);
622         return samdb_uf2acb(userAccountControl);
623 }
624
625
626 /* Find an attribute, with a particular value */
627
628 /* The current callers of this function expect a very specific
629  * behaviour: In particular, objectClass subclass equivilance is not
630  * wanted.  This means that we should not lookup the schema for the
631  * comparison function */
632 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb, 
633                                                  const struct ldb_message *msg, 
634                                                  const char *name, const char *value)
635 {
636         int i;
637         struct ldb_message_element *el = ldb_msg_find_element(msg, name);
638         struct ldb_val v;
639
640         v.data = discard_const_p(uint8_t, value);
641         v.length = strlen(value);
642
643         if (!el) {
644                 return NULL;
645         }
646
647         for (i=0;i<el->num_values;i++) {
648                 if (strcasecmp(value, (char *)el->values[i].data) == 0) {
649                         return el;
650                 }
651         }
652
653         return NULL;
654 }
655
656 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
657 {
658         if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
659                 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
660         }
661         return LDB_SUCCESS;
662 }
663
664 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
665 {
666         struct ldb_message_element *el;
667
668         el = ldb_msg_find_element(msg, name);
669         if (el) {
670                 return LDB_SUCCESS;
671         }
672                 
673         return samdb_msg_add_string(ldb, msg, msg, name, set_value);
674 }
675
676
677 /*
678   copy from a template record to a message
679 */
680 int samdb_copy_template(struct ldb_context *ldb, 
681                         struct ldb_message *msg, const char *name,
682                         const char **errstring)
683 {
684         struct ldb_result *res;
685         struct ldb_message *t;
686         int ret, i, j;
687         struct ldb_dn *basedn = ldb_dn_new(ldb, ldb, "cn=Templates");
688
689         *errstring = NULL;      
690
691         if (!ldb_dn_add_child_fmt(basedn, "CN=Template%s", name)) {
692                 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: Failed to contruct DN for template '%s'", 
693                                              name);
694                 return LDB_ERR_OPERATIONS_ERROR;
695         }
696         
697         /* pull the template record */
698         ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, "cn=*", NULL, &res);
699         talloc_free(basedn);
700         if (ret != LDB_SUCCESS) {
701                 *errstring = talloc_steal(msg, ldb_errstring(ldb));
702                 return ret;
703         }
704         if (res->count != 1) {
705                 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1", 
706                                              name, 
707                                              res->count);
708                 talloc_free(res);
709                 return LDB_ERR_OPERATIONS_ERROR;
710         }
711         t = res->msgs[0];
712
713         for (i = 0; i < t->num_elements; i++) {
714                 struct ldb_message_element *el = &t->elements[i];
715                 /* some elements should not be copied from the template */
716                 if (ldb_attr_cmp(el->name, "cn") == 0 ||
717                     ldb_attr_cmp(el->name, "name") == 0 ||
718                     ldb_attr_cmp(el->name, "objectClass") == 0 ||
719                     ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
720                     ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
721                     ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
722                     ldb_attr_cmp(el->name, "objectGUID") == 0) {
723                         continue;
724                 }
725                 for (j = 0; j < el->num_values; j++) {
726                         ret = samdb_find_or_add_attribute(ldb, msg, el->name, 
727                                                           (char *)el->values[j].data);
728                         if (ret) {
729                                 *errstring = talloc_asprintf(msg, "Adding attribute %s failed.", el->name);
730                                 talloc_free(res);
731                                 return ret;
732                         }
733                 }
734         }
735
736         talloc_free(res);
737
738         return LDB_SUCCESS;
739 }
740
741
742 /*
743   add a string element to a message
744 */
745 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
746                          const char *attr_name, const char *str)
747 {
748         char *s = talloc_strdup(mem_ctx, str);
749         char *a = talloc_strdup(mem_ctx, attr_name);
750         if (s == NULL || a == NULL) {
751                 return LDB_ERR_OPERATIONS_ERROR;
752         }
753         return ldb_msg_add_string(msg, a, s);
754 }
755
756 /*
757   add a dom_sid element to a message
758 */
759 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
760                          const char *attr_name, struct dom_sid *sid)
761 {
762         struct ldb_val v;
763         NTSTATUS status;
764         status = ndr_push_struct_blob(&v, mem_ctx, sid, 
765                                       (ndr_push_flags_fn_t)ndr_push_dom_sid);
766         if (!NT_STATUS_IS_OK(status)) {
767                 return -1;
768         }
769         return ldb_msg_add_value(msg, attr_name, &v, NULL);
770 }
771
772
773 /*
774   add a delete element operation to a message
775 */
776 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
777                          const char *attr_name)
778 {
779         /* we use an empty replace rather than a delete, as it allows for 
780            samdb_replace() to be used everywhere */
781         return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
782 }
783
784 /*
785   add a add attribute value to a message
786 */
787 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
788                          const char *attr_name, const char *value)
789 {
790         struct ldb_message_element *el;
791         char *a, *v;
792         int ret;
793         a = talloc_strdup(mem_ctx, attr_name);
794         if (a == NULL)
795                 return -1;
796         v = talloc_strdup(mem_ctx, value);
797         if (v == NULL)
798                 return -1;
799         ret = ldb_msg_add_string(msg, a, v);
800         if (ret != 0)
801                 return ret;
802         el = ldb_msg_find_element(msg, a);
803         if (el == NULL)
804                 return -1;
805         el->flags = LDB_FLAG_MOD_ADD;
806         return 0;
807 }
808
809 /*
810   add a delete attribute value to a message
811 */
812 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
813                          const char *attr_name, const char *value)
814 {
815         struct ldb_message_element *el;
816         char *a, *v;
817         int ret;
818         a = talloc_strdup(mem_ctx, attr_name);
819         if (a == NULL)
820                 return -1;
821         v = talloc_strdup(mem_ctx, value);
822         if (v == NULL)
823                 return -1;
824         ret = ldb_msg_add_string(msg, a, v);
825         if (ret != 0)
826                 return ret;
827         el = ldb_msg_find_element(msg, a);
828         if (el == NULL)
829                 return -1;
830         el->flags = LDB_FLAG_MOD_DELETE;
831         return 0;
832 }
833
834 /*
835   add a int element to a message
836 */
837 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
838                        const char *attr_name, int v)
839 {
840         const char *s = talloc_asprintf(mem_ctx, "%d", v);
841         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
842 }
843
844 /*
845   add a uint_t element to a message
846 */
847 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
848                        const char *attr_name, uint_t v)
849 {
850         const char *s = talloc_asprintf(mem_ctx, "%u", v);
851         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
852 }
853
854 /*
855   add a (signed) int64_t element to a message
856 */
857 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
858                         const char *attr_name, int64_t v)
859 {
860         const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
861         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
862 }
863
864 /*
865   add a uint64_t element to a message
866 */
867 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
868                         const char *attr_name, uint64_t v)
869 {
870         const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
871         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
872 }
873
874 /*
875   add a samr_Password element to a message
876 */
877 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
878                        const char *attr_name, struct samr_Password *hash)
879 {
880         struct ldb_val val;
881         val.data = talloc_memdup(mem_ctx, hash->hash, 16);
882         if (!val.data) {
883                 return -1;
884         }
885         val.length = 16;
886         return ldb_msg_add_value(msg, attr_name, &val, NULL);
887 }
888
889 /*
890   add a samr_Password array to a message
891 */
892 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
893                          const char *attr_name, struct samr_Password *hashes, uint_t count)
894 {
895         struct ldb_val val;
896         int i;
897         val.data = talloc_array_size(mem_ctx, 16, count);
898         val.length = count*16;
899         if (!val.data) {
900                 return -1;
901         }
902         for (i=0;i<count;i++) {
903                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
904         }
905         return ldb_msg_add_value(msg, attr_name, &val, NULL);
906 }
907
908 /*
909   add a acct_flags element to a message
910 */
911 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
912                              const char *attr_name, uint32_t v)
913 {
914         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
915 }
916
917 /*
918   add a logon_hours element to a message
919 */
920 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
921                               const char *attr_name, struct samr_LogonHours *hours)
922 {
923         struct ldb_val val;
924         val.length = hours->units_per_week / 8;
925         val.data = hours->bits;
926         return ldb_msg_add_value(msg, attr_name, &val, NULL);
927 }
928
929 /*
930   add a general value element to a message
931 */
932 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
933                               const char *attr_name, const struct ldb_val *val)
934 {
935         return ldb_msg_add_value(msg, attr_name, val, NULL);
936 }
937
938 /*
939   sets a general value element to a message
940 */
941 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
942                         const char *attr_name, const struct ldb_val *val)
943 {
944         struct ldb_message_element *el;
945
946         el = ldb_msg_find_element(msg, attr_name);
947         if (el) {
948                 el->num_values = 0;
949         }
950         return ldb_msg_add_value(msg, attr_name, val, NULL);
951 }
952
953 /*
954   set a string element in a message
955 */
956 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
957                          const char *attr_name, const char *str)
958 {
959         struct ldb_message_element *el;
960
961         el = ldb_msg_find_element(msg, attr_name);
962         if (el) {
963                 el->num_values = 0;
964         }
965         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
966 }
967
968 /*
969   add a record
970 */
971 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
972 {
973         return ldb_add(sam_ldb, msg);
974 }
975
976 /*
977   delete a record
978 */
979 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
980 {
981         return ldb_delete(sam_ldb, dn);
982 }
983
984 /*
985   modify a record
986 */
987 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
988 {
989         return ldb_modify(sam_ldb, msg);
990 }
991
992 /*
993   replace elements in a record
994 */
995 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
996 {
997         int i;
998
999         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1000         for (i=0;i<msg->num_elements;i++) {
1001                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1002         }
1003
1004         /* modify the samdb record */
1005         return samdb_modify(sam_ldb, mem_ctx, msg);
1006 }
1007
1008 /*
1009   return a default security descriptor
1010 */
1011 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1012 {
1013         struct security_descriptor *sd;
1014
1015         sd = security_descriptor_initialise(mem_ctx);
1016
1017         return sd;
1018 }
1019
1020 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx) 
1021 {
1022         return ldb_get_default_basedn(sam_ctx);
1023 }
1024
1025 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx) 
1026 {
1027         return ldb_get_config_basedn(sam_ctx);
1028 }
1029
1030 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx) 
1031 {
1032         return ldb_get_schema_basedn(sam_ctx);
1033 }
1034
1035 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx) 
1036 {
1037         return ldb_get_root_basedn(sam_ctx);
1038 }
1039
1040 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1041 {
1042         struct ldb_dn *new_dn;
1043
1044         new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1045         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1046                 talloc_free(new_dn);
1047                 return NULL;
1048         }
1049         return new_dn;
1050 }
1051
1052 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1053 {
1054         struct ldb_dn *new_dn;
1055
1056         new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1057         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1058                 talloc_free(new_dn);
1059                 return NULL;
1060         }
1061         return new_dn;
1062 }
1063
1064 /*
1065   work out the domain sid for the current open ldb
1066 */
1067 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1068 {
1069         TALLOC_CTX *tmp_ctx;
1070         struct dom_sid *domain_sid;
1071
1072         /* see if we have a cached copy */
1073         domain_sid = ldb_get_opaque(ldb, "cache.domain_sid");
1074         if (domain_sid) {
1075                 return domain_sid;
1076         }
1077
1078         tmp_ctx = talloc_new(ldb);
1079         if (tmp_ctx == NULL) {
1080                 goto failed;
1081         }
1082
1083         /* find the domain_sid */
1084         domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
1085                                           "objectSid", "objectClass=domainDNS");
1086         if (domain_sid == NULL) {
1087                 goto failed;
1088         }
1089
1090         /* cache the domain_sid in the ldb */
1091         if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1092                 goto failed;
1093         }
1094
1095         talloc_steal(ldb, domain_sid);
1096         talloc_free(tmp_ctx);
1097
1098         return domain_sid;
1099
1100 failed:
1101         DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1102         talloc_free(tmp_ctx);
1103         return NULL;
1104 }
1105
1106 /* Obtain the short name of the flexible single master operator
1107  * (FSMO), such as the PDC Emulator */
1108 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
1109                              const char *attr)
1110 {
1111         /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1112         struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1113         const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1114         const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1115
1116         if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1117                 /* Ensure this matches the format.  This gives us a
1118                  * bit more confidence that a 'cn' value will be a
1119                  * ascii string */
1120                 return NULL;
1121         }
1122         if (val) {
1123                 return (char *)val->data;
1124         }
1125         return NULL;
1126 }
1127
1128 /*
1129   work out the ntds settings dn for the current open ldb
1130 */
1131 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1132 {
1133         TALLOC_CTX *tmp_ctx;
1134         const char *root_attrs[] = { "dsServiceName", NULL };
1135         int ret;
1136         struct ldb_result *root_res;
1137         struct ldb_dn *settings_dn;
1138         
1139         /* see if we have a cached copy */
1140         settings_dn = ldb_get_opaque(ldb, "cache.settings_dn");
1141         if (settings_dn) {
1142                 return settings_dn;
1143         }
1144
1145         tmp_ctx = talloc_new(ldb);
1146         if (tmp_ctx == NULL) {
1147                 goto failed;
1148         }
1149         
1150
1151         ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1152         if (ret) {
1153                 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n", 
1154                          ldb_errstring(ldb)));
1155                 goto failed;
1156         }
1157         talloc_steal(tmp_ctx, root_res);
1158
1159         if (root_res->count != 1) {
1160                 goto failed;
1161         }
1162
1163         settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1164
1165         /* cache the domain_sid in the ldb */
1166         if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1167                 goto failed;
1168         }
1169
1170         talloc_steal(ldb, settings_dn);
1171         talloc_free(tmp_ctx);
1172
1173         return settings_dn;
1174
1175 failed:
1176         DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1177         talloc_free(tmp_ctx);
1178         return NULL;
1179 }
1180
1181 /*
1182   work out the ntds settings invocationId for the current open ldb
1183 */
1184 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1185 {
1186         TALLOC_CTX *tmp_ctx;
1187         const char *attrs[] = { "invocationId", NULL };
1188         int ret;
1189         struct ldb_result *res;
1190         struct GUID *invocation_id;
1191         
1192         /* see if we have a cached copy */
1193         invocation_id = ldb_get_opaque(ldb, "cache.invocation_id");
1194         if (invocation_id) {
1195                 return invocation_id;
1196         }
1197
1198         tmp_ctx = talloc_new(ldb);
1199         if (tmp_ctx == NULL) {
1200                 goto failed;
1201         }
1202
1203         ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1204         if (ret) {
1205                 goto failed;
1206         }
1207         talloc_steal(tmp_ctx, res);
1208
1209         if (res->count != 1) {
1210                 goto failed;
1211         }
1212
1213         invocation_id = talloc(tmp_ctx, struct GUID);
1214         if (!invocation_id) {
1215                 goto failed;
1216         }
1217
1218         *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1219
1220         /* cache the domain_sid in the ldb */
1221         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1222                 goto failed;
1223         }
1224
1225         talloc_steal(ldb, invocation_id);
1226         talloc_free(tmp_ctx);
1227
1228         return invocation_id;
1229
1230 failed:
1231         DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1232         talloc_free(tmp_ctx);
1233         return NULL;
1234 }
1235
1236 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1237 {
1238         TALLOC_CTX *tmp_ctx;
1239         struct GUID *invocation_id_new;
1240         struct GUID *invocation_id_old;
1241
1242         /* see if we have a cached copy */
1243         invocation_id_old = ldb_get_opaque(ldb, "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 = 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 = 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 }