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