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