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