r26639: librpc: Pass iconv convenience on from RPC connection to NDR library, so...
[bbaumbach/samba-autobuild/.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 /* Find a domain object in the parents of a particular DN.  */
1372 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1373                                    struct ldb_dn **parent_dn, const char **errstring)
1374 {
1375         TALLOC_CTX *local_ctx;
1376         struct ldb_dn *sdn = dn;
1377         struct ldb_result *res = NULL;
1378         int ret = 0;
1379         const char *attrs[] = { NULL };
1380
1381         local_ctx = talloc_new(mem_ctx);
1382         if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1383         
1384         while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1385                 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE, 
1386                                  "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1387                 if (ret == LDB_SUCCESS) {
1388                         talloc_steal(local_ctx, res);
1389                         if (res->count == 1) {
1390                                 break;
1391                         }
1392                 } else {
1393                         break;
1394                 }
1395         }
1396
1397         if (ret != LDB_SUCCESS) {
1398                 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1399                                              ldb_dn_get_linearized(dn),
1400                                              ldb_dn_get_linearized(sdn),
1401                                              ldb_errstring(ldb));
1402                 talloc_free(local_ctx);
1403                 return ret;
1404         }
1405         if (res->count != 1) {
1406                 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1407                                              ldb_dn_get_linearized(dn));
1408                 talloc_free(local_ctx);
1409                 return LDB_ERR_CONSTRAINT_VIOLATION;
1410         }
1411
1412         *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1413         talloc_free(local_ctx);
1414         return ret;
1415 }
1416
1417 /*
1418   check that a password is sufficiently complex
1419 */
1420 static bool samdb_password_complexity_ok(const char *pass)
1421 {
1422         return check_password_quality(pass);
1423 }
1424
1425
1426
1427 /*
1428   set the user password using plaintext, obeying any user or domain
1429   password restrictions
1430
1431   note that this function doesn't actually store the result in the
1432   database, it just fills in the "mod" structure with ldb modify
1433   elements to setup the correct change when samdb_replace() is
1434   called. This allows the caller to combine the change with other
1435   changes (as is needed by some of the set user info levels)
1436
1437   The caller should probably have a transaction wrapping this
1438 */
1439 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1440                             struct ldb_dn *user_dn,
1441                             struct ldb_dn *domain_dn,
1442                             struct ldb_message *mod,
1443                             const char *new_pass,
1444                             struct samr_Password *lmNewHash, 
1445                             struct samr_Password *ntNewHash,
1446                             bool user_change,
1447                             enum samr_RejectReason *reject_reason,
1448                             struct samr_DomInfo1 **_dominfo)
1449 {
1450         const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory", 
1451                                             "ntPwdHistory", 
1452                                             "dBCSPwd", "unicodePwd", 
1453                                             "objectSid", 
1454                                             "pwdLastSet", NULL };
1455         const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength", 
1456                                               "maxPwdAge", "minPwdAge", 
1457                                               "minPwdLength", NULL };
1458         NTTIME pwdLastSet;
1459         int64_t minPwdAge;
1460         uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1461         uint_t userAccountControl;
1462         struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1463         struct samr_Password local_lmNewHash, local_ntNewHash;
1464         int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1465         struct dom_sid *domain_sid;
1466         struct ldb_message **res;
1467         bool restrictions;
1468         int count;
1469         time_t now = time(NULL);
1470         NTTIME now_nt;
1471         int i;
1472
1473         /* we need to know the time to compute password age */
1474         unix_to_nt_time(&now_nt, now);
1475
1476         /* pull all the user parameters */
1477         count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1478         if (count != 1) {
1479                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1480         }
1481         userAccountControl = samdb_result_uint(res[0],   "userAccountControl", 0);
1482         sambaLMPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1483                                                  "lmPwdHistory", &sambaLMPwdHistory);
1484         sambaNTPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1485                                                  "ntPwdHistory", &sambaNTPwdHistory);
1486         lmPwdHash =          samdb_result_hash(mem_ctx, res[0],   "dBCSPwd");
1487         ntPwdHash =          samdb_result_hash(mem_ctx, res[0],   "unicodePwd");
1488         pwdLastSet =         samdb_result_uint64(res[0], "pwdLastSet", 0);
1489
1490         /* Only non-trust accounts have restrictions (possibly this
1491          * test is the wrong way around, but I like to be restrictive
1492          * if possible */
1493         restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1494                                                |UF_WORKSTATION_TRUST_ACCOUNT
1495                                                |UF_SERVER_TRUST_ACCOUNT)); 
1496
1497         if (domain_dn) {
1498                 /* pull the domain parameters */
1499                 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1500                 if (count != 1) {
1501                         DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n", 
1502                                   ldb_dn_get_linearized(domain_dn),
1503                                   ldb_dn_get_linearized(user_dn)));
1504                         return NT_STATUS_NO_SUCH_DOMAIN;
1505                 }
1506         } else {
1507                 /* work out the domain sid, and pull the domain from there */
1508                 domain_sid =         samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1509                 if (domain_sid == NULL) {
1510                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1511                 }
1512
1513                 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs, 
1514                                      "(objectSid=%s)", 
1515                                      ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1516                 if (count != 1) {
1517                         DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n", 
1518                                   dom_sid_string(mem_ctx, domain_sid),
1519                                   ldb_dn_get_linearized(user_dn)));
1520                         return NT_STATUS_NO_SUCH_DOMAIN;
1521                 }
1522         }
1523
1524         pwdProperties =    samdb_result_uint(res[0],   "pwdProperties", 0);
1525         pwdHistoryLength = samdb_result_uint(res[0],   "pwdHistoryLength", 0);
1526         minPwdLength =     samdb_result_uint(res[0],   "minPwdLength", 0);
1527         minPwdAge =        samdb_result_int64(res[0],  "minPwdAge", 0);
1528
1529         if (_dominfo) {
1530                 struct samr_DomInfo1 *dominfo;
1531                 /* on failure we need to fill in the reject reasons */
1532                 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1533                 if (dominfo == NULL) {
1534                         return NT_STATUS_NO_MEMORY;
1535                 }
1536                 dominfo->min_password_length     = minPwdLength;
1537                 dominfo->password_properties     = pwdProperties;
1538                 dominfo->password_history_length = pwdHistoryLength;
1539                 dominfo->max_password_age        = minPwdAge;
1540                 dominfo->min_password_age        = minPwdAge;
1541                 *_dominfo = dominfo;
1542         }
1543
1544         if (restrictions && new_pass) {
1545
1546                 /* check the various password restrictions */
1547                 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1548                         if (reject_reason) {
1549                                 *reject_reason = SAMR_REJECT_TOO_SHORT;
1550                         }
1551                         return NT_STATUS_PASSWORD_RESTRICTION;
1552                 }
1553                 
1554                 /* possibly check password complexity */
1555                 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1556                     !samdb_password_complexity_ok(new_pass)) {
1557                         if (reject_reason) {
1558                                 *reject_reason = SAMR_REJECT_COMPLEXITY;
1559                         }
1560                         return NT_STATUS_PASSWORD_RESTRICTION;
1561                 }
1562                 
1563                 /* compute the new nt and lm hashes */
1564                 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1565                         lmNewHash = &local_lmNewHash;
1566                 }
1567                 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1568                         /* If we can't convert this password to UCS2, then we should not accept it */
1569                         if (reject_reason) {
1570                                 *reject_reason = SAMR_REJECT_OTHER;
1571                         }
1572                         return NT_STATUS_PASSWORD_RESTRICTION;
1573                 }
1574                 ntNewHash = &local_ntNewHash;
1575         }
1576
1577         if (user_change) {
1578                 /* are all password changes disallowed? */
1579                 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1580                         if (reject_reason) {
1581                                 *reject_reason = SAMR_REJECT_OTHER;
1582                         }
1583                         return NT_STATUS_PASSWORD_RESTRICTION;
1584                 }
1585                 
1586                 /* can this user change password? */
1587                 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1588                         if (reject_reason) {
1589                                 *reject_reason = SAMR_REJECT_OTHER;
1590                         }
1591                         return NT_STATUS_PASSWORD_RESTRICTION;
1592                 }
1593                 
1594                 /* yes, this is a minus. The ages are in negative 100nsec units! */
1595                 if (pwdLastSet - minPwdAge > now_nt) {
1596                         if (reject_reason) {
1597                                 *reject_reason = SAMR_REJECT_OTHER;
1598                         }
1599                         return NT_STATUS_PASSWORD_RESTRICTION;
1600                 }
1601
1602                 /* check the immediately past password */
1603                 if (pwdHistoryLength > 0) {
1604                         if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1605                                 if (reject_reason) {
1606                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1607                                 }
1608                                 return NT_STATUS_PASSWORD_RESTRICTION;
1609                         }
1610                         if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1611                                 if (reject_reason) {
1612                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1613                                 }
1614                                 return NT_STATUS_PASSWORD_RESTRICTION;
1615                         }
1616                 }
1617                 
1618                 /* check the password history */
1619                 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1620                 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1621                 
1622                 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1623                         if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1624                                 if (reject_reason) {
1625                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1626                                 }
1627                                 return NT_STATUS_PASSWORD_RESTRICTION;
1628                         }
1629                 }
1630                 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1631                         if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1632                                 if (reject_reason) {
1633                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1634                                 }
1635                                 return NT_STATUS_PASSWORD_RESTRICTION;
1636                         }
1637                 }
1638         }
1639
1640 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1641
1642         /* the password is acceptable. Start forming the new fields */
1643         if (new_pass) {
1644                 /* if we know the cleartext, then only set it.
1645                  * Modules in ldb will set all the appropriate
1646                  * hashes */
1647                 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod, 
1648                                                "sambaPassword", new_pass));
1649         } else {
1650                 /* We don't have the cleartext, so delete the old one
1651                  * and set what we have of the hashes */
1652                 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1653
1654                 if (lmNewHash) {
1655                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1656                 } else {
1657                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1658                 }
1659                 
1660                 if (ntNewHash) {
1661                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1662                 } else {
1663                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1664                 }
1665         }
1666
1667         return NT_STATUS_OK;
1668 }
1669
1670
1671 /*
1672   set the user password using plaintext, obeying any user or domain
1673   password restrictions
1674
1675   This wrapper function takes a SID as input, rather than a user DN,
1676   and actually performs the password change
1677
1678 */
1679 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1680                                 const struct dom_sid *user_sid,
1681                                 const char *new_pass,
1682                                 struct samr_Password *lmNewHash, 
1683                                 struct samr_Password *ntNewHash,
1684                                 bool user_change,
1685                                 enum samr_RejectReason *reject_reason,
1686                                 struct samr_DomInfo1 **_dominfo) 
1687 {
1688         NTSTATUS nt_status;
1689         struct ldb_dn *user_dn;
1690         struct ldb_message *msg;
1691         int ret;
1692
1693         ret = ldb_transaction_start(ctx);
1694         if (ret) {
1695                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1696                 return NT_STATUS_TRANSACTION_ABORTED;
1697         }
1698
1699         user_dn = samdb_search_dn(ctx, mem_ctx, NULL, 
1700                                   "(&(objectSid=%s)(objectClass=user))", 
1701                                   ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1702         if (!user_dn) {
1703                 ldb_transaction_cancel(ctx);
1704                 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1705                           dom_sid_string(mem_ctx, user_sid)));
1706                 return NT_STATUS_NO_SUCH_USER;
1707         }
1708
1709         msg = ldb_msg_new(mem_ctx);
1710         if (msg == NULL) {
1711                 ldb_transaction_cancel(ctx);
1712                 return NT_STATUS_NO_MEMORY;
1713         }
1714
1715         msg->dn = ldb_dn_copy(msg, user_dn);
1716         if (!msg->dn) {
1717                 ldb_transaction_cancel(ctx);
1718                 return NT_STATUS_NO_MEMORY;
1719         }
1720
1721         nt_status = samdb_set_password(ctx, mem_ctx,
1722                                        user_dn, NULL,
1723                                        msg, new_pass, 
1724                                        lmNewHash, ntNewHash,
1725                                        user_change, /* This is a password set, not change */
1726                                        reject_reason, _dominfo);
1727         if (!NT_STATUS_IS_OK(nt_status)) {
1728                 ldb_transaction_cancel(ctx);
1729                 return nt_status;
1730         }
1731         
1732         /* modify the samdb record */
1733         ret = samdb_replace(ctx, mem_ctx, msg);
1734         if (ret != 0) {
1735                 ldb_transaction_cancel(ctx);
1736                 return NT_STATUS_ACCESS_DENIED;
1737         }
1738
1739         ret = ldb_transaction_commit(ctx);
1740         if (ret != 0) {
1741                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1742                          ldb_dn_get_linearized(msg->dn),
1743                          ldb_errstring(ctx)));
1744                 return NT_STATUS_TRANSACTION_ABORTED;
1745         }
1746         return NT_STATUS_OK;
1747 }
1748
1749
1750
1751 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
1752                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
1753 {
1754         struct ldb_message *msg;
1755         struct ldb_dn *basedn;
1756         const char *sidstr;
1757         int ret;
1758         
1759         sidstr = dom_sid_string(mem_ctx, sid);
1760         NT_STATUS_HAVE_NO_MEMORY(sidstr);
1761         
1762         /* We might have to create a ForeignSecurityPrincipal, even if this user
1763          * is in our own domain */
1764         
1765         msg = ldb_msg_new(mem_ctx);
1766         if (msg == NULL) {
1767                 return NT_STATUS_NO_MEMORY;
1768         }
1769         
1770         /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1771          * put the ForeignSecurityPrincipals? d_state->domain_dn does
1772          * not work, this is wrong for the Builtin domain, there's no
1773          * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
1774          */
1775         
1776         basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1777                                  "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1778         
1779         if (basedn == NULL) {
1780                 DEBUG(0, ("Failed to find DN for "
1781                           "ForeignSecurityPrincipal container\n"));
1782                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1783         }
1784         
1785         /* add core elements to the ldb_message for the alias */
1786         msg->dn = ldb_dn_copy(mem_ctx, basedn);
1787         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1788                 return NT_STATUS_NO_MEMORY;
1789         
1790         samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1791                              "objectClass",
1792                              "foreignSecurityPrincipal");
1793         
1794         /* create the alias */
1795         ret = ldb_add(sam_ctx, msg);
1796         if (ret != 0) {
1797                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1798                          "record %s: %s\n", 
1799                          ldb_dn_get_linearized(msg->dn),
1800                          ldb_errstring(sam_ctx)));
1801                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1802         }
1803         *ret_dn = msg->dn;
1804         return NT_STATUS_OK;
1805 }
1806
1807
1808 /*
1809   Find the DN of a domain, assuming it to be a dotted.dns name
1810 */
1811
1812 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) 
1813 {
1814         int i;
1815         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1816         const char *binary_encoded;
1817         const char **split_realm;
1818         struct ldb_dn *dn;
1819         
1820         if (!tmp_ctx) {
1821                 return NULL;
1822         }
1823         
1824         split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1825         if (!split_realm) {
1826                 talloc_free(tmp_ctx);
1827                 return NULL;
1828         }
1829         dn = ldb_dn_new(mem_ctx, ldb, NULL);
1830         for (i=0; split_realm[i]; i++) {
1831                 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1832                 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1833                         DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1834                                   binary_encoded, ldb_dn_get_linearized(dn)));
1835                         talloc_free(tmp_ctx);
1836                         return NULL;
1837                 }
1838         }
1839         if (!ldb_dn_validate(dn)) {
1840                 DEBUG(2, ("Failed to validated DN %s\n",
1841                           ldb_dn_get_linearized(dn)));
1842                 return NULL;
1843         }
1844         return dn;
1845 }
1846 /*
1847   Find the DN of a domain, be it the netbios or DNS name 
1848 */
1849
1850 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
1851                                   const char *domain_name) 
1852 {
1853         const char * const domain_ref_attrs[] = {
1854                 "ncName", NULL
1855         };
1856         const char * const domain_ref2_attrs[] = {
1857                 NULL
1858         };
1859         struct ldb_result *res_domain_ref;
1860         char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1861         /* find the domain's DN */
1862         int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx, 
1863                                             &res_domain_ref, 
1864                                             samdb_partitions_dn(ldb, mem_ctx), 
1865                                             LDB_SCOPE_ONELEVEL, 
1866                                             domain_ref_attrs,
1867                                             "(&(nETBIOSName=%s)(objectclass=crossRef))", 
1868                                             escaped_domain);
1869         if (ret_domain != 0) {
1870                 return NULL;
1871         }
1872         
1873         if (res_domain_ref->count == 0) {
1874                 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx, 
1875                                                 &res_domain_ref, 
1876                                                 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
1877                                                 LDB_SCOPE_BASE,
1878                                                 domain_ref2_attrs,
1879                                                 "(objectclass=domain)");
1880                 if (ret_domain != 0) {
1881                         return NULL;
1882                 }
1883         
1884                 if (res_domain_ref->count == 1) {
1885                         return res_domain_ref->msgs[0]->dn;
1886                 }
1887                 return NULL;
1888         }
1889         
1890         if (res_domain_ref->count > 1) {
1891                 DEBUG(0,("Found %d records matching domain [%s]\n", 
1892                          ret_domain, domain_name));
1893                 return NULL;
1894         }
1895         
1896         return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
1897
1898 }