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