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