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