r26298: Use metze's schema loading code to pre-initialise the schema into the
[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 "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, (struct loadparm_context *)ldb_get_opaque(ldb, "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 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1140 {
1141         TALLOC_CTX *tmp_ctx;
1142         struct dom_sid *dom_sid_new;
1143         struct dom_sid *dom_sid_old;
1144
1145         /* see if we have a cached copy */
1146         dom_sid_old = talloc_get_type(ldb_get_opaque(ldb, 
1147                                                      "cache.domain_sid"), struct dom_sid);
1148
1149         tmp_ctx = talloc_new(ldb);
1150         if (tmp_ctx == NULL) {
1151                 goto failed;
1152         }
1153
1154         dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1155         if (!dom_sid_new) {
1156                 goto failed;
1157         }
1158
1159         /* cache the domain_sid in the ldb */
1160         if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1161                 goto failed;
1162         }
1163
1164         talloc_steal(ldb, dom_sid_new);
1165         talloc_free(tmp_ctx);
1166         talloc_free(dom_sid_old);
1167
1168         return true;
1169
1170 failed:
1171         DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1172         talloc_free(tmp_ctx);
1173         return false;
1174 }
1175
1176 /* Obtain the short name of the flexible single master operator
1177  * (FSMO), such as the PDC Emulator */
1178 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
1179                              const char *attr)
1180 {
1181         /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1182         struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1183         const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1184         const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1185
1186         if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1187                 /* Ensure this matches the format.  This gives us a
1188                  * bit more confidence that a 'cn' value will be a
1189                  * ascii string */
1190                 return NULL;
1191         }
1192         if (val) {
1193                 return (char *)val->data;
1194         }
1195         return NULL;
1196 }
1197
1198 /*
1199   work out the ntds settings dn for the current open ldb
1200 */
1201 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1202 {
1203         TALLOC_CTX *tmp_ctx;
1204         const char *root_attrs[] = { "dsServiceName", NULL };
1205         int ret;
1206         struct ldb_result *root_res;
1207         struct ldb_dn *settings_dn;
1208         
1209         /* see if we have a cached copy */
1210         settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1211         if (settings_dn) {
1212                 return settings_dn;
1213         }
1214
1215         tmp_ctx = talloc_new(ldb);
1216         if (tmp_ctx == NULL) {
1217                 goto failed;
1218         }
1219         
1220
1221         ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1222         if (ret) {
1223                 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n", 
1224                          ldb_errstring(ldb)));
1225                 goto failed;
1226         }
1227         talloc_steal(tmp_ctx, root_res);
1228
1229         if (root_res->count != 1) {
1230                 goto failed;
1231         }
1232
1233         settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1234
1235         /* cache the domain_sid in the ldb */
1236         if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1237                 goto failed;
1238         }
1239
1240         talloc_steal(ldb, settings_dn);
1241         talloc_free(tmp_ctx);
1242
1243         return settings_dn;
1244
1245 failed:
1246         DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1247         talloc_free(tmp_ctx);
1248         return NULL;
1249 }
1250
1251 /*
1252   work out the ntds settings invocationId for the current open ldb
1253 */
1254 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1255 {
1256         TALLOC_CTX *tmp_ctx;
1257         const char *attrs[] = { "invocationId", NULL };
1258         int ret;
1259         struct ldb_result *res;
1260         struct GUID *invocation_id;
1261         
1262         /* see if we have a cached copy */
1263         invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1264         if (invocation_id) {
1265                 return invocation_id;
1266         }
1267
1268         tmp_ctx = talloc_new(ldb);
1269         if (tmp_ctx == NULL) {
1270                 goto failed;
1271         }
1272
1273         ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1274         if (ret) {
1275                 goto failed;
1276         }
1277         talloc_steal(tmp_ctx, res);
1278
1279         if (res->count != 1) {
1280                 goto failed;
1281         }
1282
1283         invocation_id = talloc(tmp_ctx, struct GUID);
1284         if (!invocation_id) {
1285                 goto failed;
1286         }
1287
1288         *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1289
1290         /* cache the domain_sid in the ldb */
1291         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1292                 goto failed;
1293         }
1294
1295         talloc_steal(ldb, invocation_id);
1296         talloc_free(tmp_ctx);
1297
1298         return invocation_id;
1299
1300 failed:
1301         DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1302         talloc_free(tmp_ctx);
1303         return NULL;
1304 }
1305
1306 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1307 {
1308         TALLOC_CTX *tmp_ctx;
1309         struct GUID *invocation_id_new;
1310         struct GUID *invocation_id_old;
1311
1312         /* see if we have a cached copy */
1313         invocation_id_old = (struct GUID *)ldb_get_opaque(ldb, 
1314                                                          "cache.invocation_id");
1315
1316         tmp_ctx = talloc_new(ldb);
1317         if (tmp_ctx == NULL) {
1318                 goto failed;
1319         }
1320
1321         invocation_id_new = talloc(tmp_ctx, struct GUID);
1322         if (!invocation_id_new) {
1323                 goto failed;
1324         }
1325
1326         *invocation_id_new = *invocation_id_in;
1327
1328         /* cache the domain_sid in the ldb */
1329         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1330                 goto failed;
1331         }
1332
1333         talloc_steal(ldb, invocation_id_new);
1334         talloc_free(tmp_ctx);
1335         talloc_free(invocation_id_old);
1336
1337         return true;
1338
1339 failed:
1340         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1341         talloc_free(tmp_ctx);
1342         return false;
1343 }
1344
1345 /*
1346   work out the ntds settings objectGUID for the current open ldb
1347 */
1348 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1349 {
1350         TALLOC_CTX *tmp_ctx;
1351         const char *attrs[] = { "objectGUID", NULL };
1352         int ret;
1353         struct ldb_result *res;
1354         struct GUID *ntds_guid;
1355         
1356         /* see if we have a cached copy */
1357         ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1358         if (ntds_guid) {
1359                 return ntds_guid;
1360         }
1361
1362         tmp_ctx = talloc_new(ldb);
1363         if (tmp_ctx == NULL) {
1364                 goto failed;
1365         }
1366
1367         ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1368         if (ret) {
1369                 goto failed;
1370         }
1371         talloc_steal(tmp_ctx, res);
1372
1373         if (res->count != 1) {
1374                 goto failed;
1375         }
1376
1377         ntds_guid = talloc(tmp_ctx, struct GUID);
1378         if (!ntds_guid) {
1379                 goto failed;
1380         }
1381
1382         *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1383
1384         /* cache the domain_sid in the ldb */
1385         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1386                 goto failed;
1387         }
1388
1389         talloc_steal(ldb, ntds_guid);
1390         talloc_free(tmp_ctx);
1391
1392         return ntds_guid;
1393
1394 failed:
1395         DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1396         talloc_free(tmp_ctx);
1397         return NULL;
1398 }
1399
1400 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1401 {
1402         TALLOC_CTX *tmp_ctx;
1403         struct GUID *ntds_guid_new;
1404         struct GUID *ntds_guid_old;
1405         
1406         /* see if we have a cached copy */
1407         ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1408
1409         tmp_ctx = talloc_new(ldb);
1410         if (tmp_ctx == NULL) {
1411                 goto failed;
1412         }
1413
1414         ntds_guid_new = talloc(tmp_ctx, struct GUID);
1415         if (!ntds_guid_new) {
1416                 goto failed;
1417         }
1418
1419         *ntds_guid_new = *ntds_guid_in;
1420
1421         /* cache the domain_sid in the ldb */
1422         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1423                 goto failed;
1424         }
1425
1426         talloc_steal(ldb, ntds_guid_new);
1427         talloc_free(tmp_ctx);
1428         talloc_free(ntds_guid_old);
1429
1430         return true;
1431
1432 failed:
1433         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1434         talloc_free(tmp_ctx);
1435         return false;
1436 }
1437
1438 /*
1439   work out the server dn for the current open ldb
1440 */
1441 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1442 {
1443         return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1444 }
1445
1446 /*
1447   work out the server dn for the current open ldb
1448 */
1449 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1450 {
1451         struct ldb_dn *server_dn;
1452         struct ldb_dn *server_site_dn;
1453
1454         server_dn = samdb_server_dn(ldb, mem_ctx);
1455         if (!server_dn) return NULL;
1456
1457         server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1458
1459         talloc_free(server_dn);
1460         return server_site_dn;
1461 }
1462
1463 /*
1464   work out if we are the PDC for the domain of the current open ldb
1465 */
1466 bool samdb_is_pdc(struct ldb_context *ldb)
1467 {
1468         const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1469         int ret;
1470         struct ldb_result *dom_res;
1471         TALLOC_CTX *tmp_ctx;
1472         bool is_pdc;
1473         struct ldb_dn *pdc;
1474
1475         tmp_ctx = talloc_new(ldb);
1476         if (tmp_ctx == NULL) {
1477                 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1478                 return false;
1479         }
1480
1481         ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1482         if (ret) {
1483                 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n", 
1484                          ldb_dn_get_linearized(ldb_get_default_basedn(ldb)), 
1485                          ldb_errstring(ldb)));
1486                 goto failed;
1487         }
1488         talloc_steal(tmp_ctx, dom_res);
1489         if (dom_res->count != 1) {
1490                 goto failed;
1491         }
1492
1493         pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1494
1495         if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1496                 is_pdc = true;
1497         } else {
1498                 is_pdc = false;
1499         }
1500
1501         talloc_free(tmp_ctx);
1502
1503         return is_pdc;
1504
1505 failed:
1506         DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1507         talloc_free(tmp_ctx);
1508         return false;
1509 }
1510
1511
1512 /* Find a domain object in the parents of a particular DN.  */
1513 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1514                                    struct ldb_dn **parent_dn, const char **errstring)
1515 {
1516         TALLOC_CTX *local_ctx;
1517         struct ldb_dn *sdn = dn;
1518         struct ldb_result *res = NULL;
1519         int ret = 0;
1520         const char *attrs[] = { NULL };
1521
1522         local_ctx = talloc_new(mem_ctx);
1523         if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1524         
1525         while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1526                 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE, 
1527                                  "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1528                 if (ret == LDB_SUCCESS) {
1529                         talloc_steal(local_ctx, res);
1530                         if (res->count == 1) {
1531                                 break;
1532                         }
1533                 } else {
1534                         break;
1535                 }
1536         }
1537
1538         if (ret != LDB_SUCCESS) {
1539                 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1540                                              ldb_dn_get_linearized(dn),
1541                                              ldb_dn_get_linearized(sdn),
1542                                              ldb_errstring(ldb));
1543                 talloc_free(local_ctx);
1544                 return ret;
1545         }
1546         if (res->count != 1) {
1547                 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1548                                              ldb_dn_get_linearized(dn));
1549                 talloc_free(local_ctx);
1550                 return LDB_ERR_CONSTRAINT_VIOLATION;
1551         }
1552
1553         *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1554         talloc_free(local_ctx);
1555         return ret;
1556 }
1557
1558 /*
1559   check that a password is sufficiently complex
1560 */
1561 static bool samdb_password_complexity_ok(const char *pass)
1562 {
1563         return check_password_quality(pass);
1564 }
1565
1566
1567
1568 /*
1569   set the user password using plaintext, obeying any user or domain
1570   password restrictions
1571
1572   note that this function doesn't actually store the result in the
1573   database, it just fills in the "mod" structure with ldb modify
1574   elements to setup the correct change when samdb_replace() is
1575   called. This allows the caller to combine the change with other
1576   changes (as is needed by some of the set user info levels)
1577
1578   The caller should probably have a transaction wrapping this
1579 */
1580 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1581                             struct ldb_dn *user_dn,
1582                             struct ldb_dn *domain_dn,
1583                             struct ldb_message *mod,
1584                             const char *new_pass,
1585                             struct samr_Password *lmNewHash, 
1586                             struct samr_Password *ntNewHash,
1587                             bool user_change,
1588                             enum samr_RejectReason *reject_reason,
1589                             struct samr_DomInfo1 **_dominfo)
1590 {
1591         const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory", 
1592                                             "ntPwdHistory", 
1593                                             "dBCSPwd", "unicodePwd", 
1594                                             "objectSid", 
1595                                             "pwdLastSet", NULL };
1596         const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength", 
1597                                               "maxPwdAge", "minPwdAge", 
1598                                               "minPwdLength", NULL };
1599         NTTIME pwdLastSet;
1600         int64_t minPwdAge;
1601         uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1602         uint_t userAccountControl;
1603         struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1604         struct samr_Password local_lmNewHash, local_ntNewHash;
1605         int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1606         struct dom_sid *domain_sid;
1607         struct ldb_message **res;
1608         bool restrictions;
1609         int count;
1610         time_t now = time(NULL);
1611         NTTIME now_nt;
1612         int i;
1613
1614         /* we need to know the time to compute password age */
1615         unix_to_nt_time(&now_nt, now);
1616
1617         /* pull all the user parameters */
1618         count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1619         if (count != 1) {
1620                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1621         }
1622         userAccountControl = samdb_result_uint(res[0],   "userAccountControl", 0);
1623         sambaLMPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1624                                                  "lmPwdHistory", &sambaLMPwdHistory);
1625         sambaNTPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1626                                                  "ntPwdHistory", &sambaNTPwdHistory);
1627         lmPwdHash =          samdb_result_hash(mem_ctx, res[0],   "dBCSPwd");
1628         ntPwdHash =          samdb_result_hash(mem_ctx, res[0],   "unicodePwd");
1629         pwdLastSet =         samdb_result_uint64(res[0], "pwdLastSet", 0);
1630
1631         /* Only non-trust accounts have restrictions (possibly this
1632          * test is the wrong way around, but I like to be restrictive
1633          * if possible */
1634         restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1635                                                |UF_WORKSTATION_TRUST_ACCOUNT
1636                                                |UF_SERVER_TRUST_ACCOUNT)); 
1637
1638         if (domain_dn) {
1639                 /* pull the domain parameters */
1640                 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1641                 if (count != 1) {
1642                         DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n", 
1643                                   ldb_dn_get_linearized(domain_dn),
1644                                   ldb_dn_get_linearized(user_dn)));
1645                         return NT_STATUS_NO_SUCH_DOMAIN;
1646                 }
1647         } else {
1648                 /* work out the domain sid, and pull the domain from there */
1649                 domain_sid =         samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1650                 if (domain_sid == NULL) {
1651                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1652                 }
1653
1654                 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs, 
1655                                      "(objectSid=%s)", 
1656                                      ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1657                 if (count != 1) {
1658                         DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n", 
1659                                   dom_sid_string(mem_ctx, domain_sid),
1660                                   ldb_dn_get_linearized(user_dn)));
1661                         return NT_STATUS_NO_SUCH_DOMAIN;
1662                 }
1663         }
1664
1665         pwdProperties =    samdb_result_uint(res[0],   "pwdProperties", 0);
1666         pwdHistoryLength = samdb_result_uint(res[0],   "pwdHistoryLength", 0);
1667         minPwdLength =     samdb_result_uint(res[0],   "minPwdLength", 0);
1668         minPwdAge =        samdb_result_int64(res[0],  "minPwdAge", 0);
1669
1670         if (_dominfo) {
1671                 struct samr_DomInfo1 *dominfo;
1672                 /* on failure we need to fill in the reject reasons */
1673                 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1674                 if (dominfo == NULL) {
1675                         return NT_STATUS_NO_MEMORY;
1676                 }
1677                 dominfo->min_password_length     = minPwdLength;
1678                 dominfo->password_properties     = pwdProperties;
1679                 dominfo->password_history_length = pwdHistoryLength;
1680                 dominfo->max_password_age        = minPwdAge;
1681                 dominfo->min_password_age        = minPwdAge;
1682                 *_dominfo = dominfo;
1683         }
1684
1685         if (restrictions && new_pass) {
1686
1687                 /* check the various password restrictions */
1688                 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1689                         if (reject_reason) {
1690                                 *reject_reason = SAMR_REJECT_TOO_SHORT;
1691                         }
1692                         return NT_STATUS_PASSWORD_RESTRICTION;
1693                 }
1694                 
1695                 /* possibly check password complexity */
1696                 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1697                     !samdb_password_complexity_ok(new_pass)) {
1698                         if (reject_reason) {
1699                                 *reject_reason = SAMR_REJECT_COMPLEXITY;
1700                         }
1701                         return NT_STATUS_PASSWORD_RESTRICTION;
1702                 }
1703                 
1704                 /* compute the new nt and lm hashes */
1705                 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1706                         lmNewHash = &local_lmNewHash;
1707                 }
1708                 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1709                         /* If we can't convert this password to UCS2, then we should not accept it */
1710                         if (reject_reason) {
1711                                 *reject_reason = SAMR_REJECT_OTHER;
1712                         }
1713                         return NT_STATUS_PASSWORD_RESTRICTION;
1714                 }
1715                 ntNewHash = &local_ntNewHash;
1716         }
1717
1718         if (user_change) {
1719                 /* are all password changes disallowed? */
1720                 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1721                         if (reject_reason) {
1722                                 *reject_reason = SAMR_REJECT_OTHER;
1723                         }
1724                         return NT_STATUS_PASSWORD_RESTRICTION;
1725                 }
1726                 
1727                 /* can this user change password? */
1728                 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1729                         if (reject_reason) {
1730                                 *reject_reason = SAMR_REJECT_OTHER;
1731                         }
1732                         return NT_STATUS_PASSWORD_RESTRICTION;
1733                 }
1734                 
1735                 /* yes, this is a minus. The ages are in negative 100nsec units! */
1736                 if (pwdLastSet - minPwdAge > now_nt) {
1737                         if (reject_reason) {
1738                                 *reject_reason = SAMR_REJECT_OTHER;
1739                         }
1740                         return NT_STATUS_PASSWORD_RESTRICTION;
1741                 }
1742
1743                 /* check the immediately past password */
1744                 if (pwdHistoryLength > 0) {
1745                         if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1746                                 if (reject_reason) {
1747                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1748                                 }
1749                                 return NT_STATUS_PASSWORD_RESTRICTION;
1750                         }
1751                         if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1752                                 if (reject_reason) {
1753                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1754                                 }
1755                                 return NT_STATUS_PASSWORD_RESTRICTION;
1756                         }
1757                 }
1758                 
1759                 /* check the password history */
1760                 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1761                 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1762                 
1763                 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1764                         if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1765                                 if (reject_reason) {
1766                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1767                                 }
1768                                 return NT_STATUS_PASSWORD_RESTRICTION;
1769                         }
1770                 }
1771                 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1772                         if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1773                                 if (reject_reason) {
1774                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1775                                 }
1776                                 return NT_STATUS_PASSWORD_RESTRICTION;
1777                         }
1778                 }
1779         }
1780
1781 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1782
1783         /* the password is acceptable. Start forming the new fields */
1784         if (new_pass) {
1785                 /* if we know the cleartext, then only set it.
1786                  * Modules in ldb will set all the appropriate
1787                  * hashes */
1788                 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod, 
1789                                                "sambaPassword", new_pass));
1790         } else {
1791                 /* We don't have the cleartext, so delete the old one
1792                  * and set what we have of the hashes */
1793                 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1794
1795                 if (lmNewHash) {
1796                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1797                 } else {
1798                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1799                 }
1800                 
1801                 if (ntNewHash) {
1802                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1803                 } else {
1804                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1805                 }
1806         }
1807
1808         return NT_STATUS_OK;
1809 }
1810
1811
1812 /*
1813   set the user password using plaintext, obeying any user or domain
1814   password restrictions
1815
1816   This wrapper function takes a SID as input, rather than a user DN,
1817   and actually performs the password change
1818
1819 */
1820 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1821                                 const struct dom_sid *user_sid,
1822                                 const char *new_pass,
1823                                 struct samr_Password *lmNewHash, 
1824                                 struct samr_Password *ntNewHash,
1825                                 bool user_change,
1826                                 enum samr_RejectReason *reject_reason,
1827                                 struct samr_DomInfo1 **_dominfo) 
1828 {
1829         NTSTATUS nt_status;
1830         struct ldb_dn *user_dn;
1831         struct ldb_message *msg;
1832         int ret;
1833
1834         ret = ldb_transaction_start(ctx);
1835         if (ret) {
1836                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1837                 return NT_STATUS_TRANSACTION_ABORTED;
1838         }
1839
1840         user_dn = samdb_search_dn(ctx, mem_ctx, NULL, 
1841                                   "(&(objectSid=%s)(objectClass=user))", 
1842                                   ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1843         if (!user_dn) {
1844                 ldb_transaction_cancel(ctx);
1845                 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1846                           dom_sid_string(mem_ctx, user_sid)));
1847                 return NT_STATUS_NO_SUCH_USER;
1848         }
1849
1850         msg = ldb_msg_new(mem_ctx);
1851         if (msg == NULL) {
1852                 ldb_transaction_cancel(ctx);
1853                 return NT_STATUS_NO_MEMORY;
1854         }
1855
1856         msg->dn = ldb_dn_copy(msg, user_dn);
1857         if (!msg->dn) {
1858                 ldb_transaction_cancel(ctx);
1859                 return NT_STATUS_NO_MEMORY;
1860         }
1861
1862         nt_status = samdb_set_password(ctx, mem_ctx,
1863                                        user_dn, NULL,
1864                                        msg, new_pass, 
1865                                        lmNewHash, ntNewHash,
1866                                        user_change, /* This is a password set, not change */
1867                                        reject_reason, _dominfo);
1868         if (!NT_STATUS_IS_OK(nt_status)) {
1869                 ldb_transaction_cancel(ctx);
1870                 return nt_status;
1871         }
1872         
1873         /* modify the samdb record */
1874         ret = samdb_replace(ctx, mem_ctx, msg);
1875         if (ret != 0) {
1876                 ldb_transaction_cancel(ctx);
1877                 return NT_STATUS_ACCESS_DENIED;
1878         }
1879
1880         ret = ldb_transaction_commit(ctx);
1881         if (ret != 0) {
1882                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1883                          ldb_dn_get_linearized(msg->dn),
1884                          ldb_errstring(ctx)));
1885                 return NT_STATUS_TRANSACTION_ABORTED;
1886         }
1887         return NT_STATUS_OK;
1888 }
1889
1890 /****************************************************************************
1891  Create the SID list for this user.
1892 ****************************************************************************/
1893 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx, 
1894                                struct loadparm_context *lp_ctx,
1895                                struct dom_sid *user_sid,
1896                                struct dom_sid *group_sid, 
1897                                int n_groupSIDs,
1898                                struct dom_sid **groupSIDs, 
1899                                bool is_authenticated,
1900                                struct security_token **token)
1901 {
1902         struct security_token *ptoken;
1903         int i;
1904         NTSTATUS status;
1905
1906         ptoken = security_token_initialise(mem_ctx);
1907         NT_STATUS_HAVE_NO_MEMORY(ptoken);
1908
1909         ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1910         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1911
1912         ptoken->user_sid = talloc_reference(ptoken, user_sid);
1913         ptoken->group_sid = talloc_reference(ptoken, group_sid);
1914         ptoken->privilege_mask = 0;
1915
1916         ptoken->sids[0] = ptoken->user_sid;
1917         ptoken->sids[1] = ptoken->group_sid;
1918
1919         /*
1920          * Finally add the "standard" SIDs.
1921          * The only difference between guest and "anonymous"
1922          * is the addition of Authenticated_Users.
1923          */
1924         ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1925         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1926         ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1927         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1928         ptoken->num_sids = 4;
1929
1930         if (is_authenticated) {
1931                 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1932                 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1933                 ptoken->num_sids++;
1934         }
1935
1936         for (i = 0; i < n_groupSIDs; i++) {
1937                 size_t check_sid_idx;
1938                 for (check_sid_idx = 1; 
1939                      check_sid_idx < ptoken->num_sids; 
1940                      check_sid_idx++) {
1941                         if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1942                                 break;
1943                         }
1944                 }
1945
1946                 if (check_sid_idx == ptoken->num_sids) {
1947                         ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1948                 }
1949         }
1950
1951         /* setup the privilege mask for this token */
1952         status = samdb_privilege_setup(lp_ctx, ptoken);
1953         if (!NT_STATUS_IS_OK(status)) {
1954                 talloc_free(ptoken);
1955                 return status;
1956         }
1957
1958         security_token_debug(10, ptoken);
1959
1960         *token = ptoken;
1961
1962         return NT_STATUS_OK;
1963 }
1964
1965
1966 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
1967                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
1968 {
1969         struct ldb_message *msg;
1970         struct ldb_dn *basedn;
1971         const char *sidstr;
1972         int ret;
1973         
1974         sidstr = dom_sid_string(mem_ctx, sid);
1975         NT_STATUS_HAVE_NO_MEMORY(sidstr);
1976         
1977         /* We might have to create a ForeignSecurityPrincipal, even if this user
1978          * is in our own domain */
1979         
1980         msg = ldb_msg_new(mem_ctx);
1981         if (msg == NULL) {
1982                 return NT_STATUS_NO_MEMORY;
1983         }
1984         
1985         /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1986          * put the ForeignSecurityPrincipals? d_state->domain_dn does
1987          * not work, this is wrong for the Builtin domain, there's no
1988          * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
1989          */
1990         
1991         basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1992                                  "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1993         
1994         if (basedn == NULL) {
1995                 DEBUG(0, ("Failed to find DN for "
1996                           "ForeignSecurityPrincipal container\n"));
1997                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1998         }
1999         
2000         /* add core elements to the ldb_message for the alias */
2001         msg->dn = ldb_dn_copy(mem_ctx, basedn);
2002         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
2003                 return NT_STATUS_NO_MEMORY;
2004         
2005         samdb_msg_add_string(sam_ctx, mem_ctx, msg,
2006                              "objectClass",
2007                              "foreignSecurityPrincipal");
2008         
2009         /* create the alias */
2010         ret = ldb_add(sam_ctx, msg);
2011         if (ret != 0) {
2012                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2013                          "record %s: %s\n", 
2014                          ldb_dn_get_linearized(msg->dn),
2015                          ldb_errstring(sam_ctx)));
2016                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2017         }
2018         *ret_dn = msg->dn;
2019         return NT_STATUS_OK;
2020 }
2021
2022
2023 /*
2024   Find the DN of a domain, assuming it to be a dotted.dns name
2025 */
2026
2027 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) 
2028 {
2029         int i;
2030         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2031         const char *binary_encoded;
2032         const char **split_realm;
2033         struct ldb_dn *dn;
2034         
2035         if (!tmp_ctx) {
2036                 return NULL;
2037         }
2038         
2039         split_realm = str_list_make(tmp_ctx, dns_domain, ".");
2040         if (!split_realm) {
2041                 talloc_free(tmp_ctx);
2042                 return NULL;
2043         }
2044         dn = ldb_dn_new(mem_ctx, ldb, NULL);
2045         for (i=0; split_realm[i]; i++) {
2046                 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2047                 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2048                         DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2049                                   binary_encoded, ldb_dn_get_linearized(dn)));
2050                         talloc_free(tmp_ctx);
2051                         return NULL;
2052                 }
2053         }
2054         if (!ldb_dn_validate(dn)) {
2055                 DEBUG(2, ("Failed to validated DN %s\n",
2056                           ldb_dn_get_linearized(dn)));
2057                 return NULL;
2058         }
2059         return dn;
2060 }
2061 /*
2062   Find the DN of a domain, be it the netbios or DNS name 
2063 */
2064
2065 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
2066                                   const char *domain_name) 
2067 {
2068         const char * const domain_ref_attrs[] = {
2069                 "ncName", NULL
2070         };
2071         const char * const domain_ref2_attrs[] = {
2072                 NULL
2073         };
2074         struct ldb_result *res_domain_ref;
2075         char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2076         /* find the domain's DN */
2077         int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx, 
2078                                             &res_domain_ref, 
2079                                             samdb_partitions_dn(ldb, mem_ctx), 
2080                                             LDB_SCOPE_ONELEVEL, 
2081                                             domain_ref_attrs,
2082                                             "(&(nETBIOSName=%s)(objectclass=crossRef))", 
2083                                             escaped_domain);
2084         if (ret_domain != 0) {
2085                 return NULL;
2086         }
2087         
2088         if (res_domain_ref->count == 0) {
2089                 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx, 
2090                                                 &res_domain_ref, 
2091                                                 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2092                                                 LDB_SCOPE_BASE,
2093                                                 domain_ref2_attrs,
2094                                                 "(objectclass=domain)");
2095                 if (ret_domain != 0) {
2096                         return NULL;
2097                 }
2098         
2099                 if (res_domain_ref->count == 1) {
2100                         return res_domain_ref->msgs[0]->dn;
2101                 }
2102                 return NULL;
2103         }
2104         
2105         if (res_domain_ref->count > 1) {
2106                 DEBUG(0,("Found %d records matching domain [%s]\n", 
2107                          ret_domain, domain_name));
2108                 return NULL;
2109         }
2110         
2111         return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2112
2113 }