check-password-script: Allow AD to execute these scripts
[sharpe/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 "events/events.h"
26 #include "ldb.h"
27 #include "ldb_module.h"
28 #include "ldb_errors.h"
29 #include "../lib/util/util_ldb.h"
30 #include "../lib/crypto/crypto.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_security.h"
34 #include "librpc/gen_ndr/ndr_misc.h"
35 #include "../libds/common/flags.h"
36 #include "dsdb/common/proto.h"
37 #include "libcli/ldap/ldap_ndr.h"
38 #include "param/param.h"
39 #include "libcli/auth/libcli_auth.h"
40 #include "librpc/gen_ndr/ndr_drsblobs.h"
41 #include "system/locale.h"
42 #include "lib/util/tsort.h"
43 #include "dsdb/common/util.h"
44 #include "lib/socket/socket.h"
45 #include "librpc/gen_ndr/irpc.h"
46 #include "libds/common/flag_mapping.h"
47 #include "../lib/util/util_runcmd.h"
48
49 /*
50   search the sam for the specified attributes in a specific domain, filter on
51   objectSid being in domain_sid.
52 */
53 int samdb_search_domain(struct ldb_context *sam_ldb,
54                         TALLOC_CTX *mem_ctx, 
55                         struct ldb_dn *basedn,
56                         struct ldb_message ***res,
57                         const char * const *attrs,
58                         const struct dom_sid *domain_sid,
59                         const char *format, ...)  _PRINTF_ATTRIBUTE(7,8)
60 {
61         va_list ap;
62         int i, count;
63
64         va_start(ap, format);
65         count = gendb_search_v(sam_ldb, mem_ctx, basedn,
66                                res, attrs, format, ap);
67         va_end(ap);
68
69         i=0;
70
71         while (i<count) {
72                 struct dom_sid *entry_sid;
73
74                 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
75
76                 if ((entry_sid == NULL) ||
77                     (!dom_sid_in_domain(domain_sid, entry_sid))) {
78                         /* Delete that entry from the result set */
79                         (*res)[i] = (*res)[count-1];
80                         count -= 1;
81                         talloc_free(entry_sid);
82                         continue;
83                 }
84                 talloc_free(entry_sid);
85                 i += 1;
86         }
87
88         return count;
89 }
90
91 /*
92   search the sam for a single string attribute in exactly 1 record
93 */
94 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
95                                   TALLOC_CTX *mem_ctx,
96                                   struct ldb_dn *basedn,
97                                   const char *attr_name,
98                                   const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
99 {
100         int count;
101         const char *attrs[2] = { NULL, NULL };
102         struct ldb_message **res = NULL;
103
104         attrs[0] = attr_name;
105
106         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
107         if (count > 1) {                
108                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
109                          attr_name, format, count));
110         }
111         if (count != 1) {
112                 talloc_free(res);
113                 return NULL;
114         }
115
116         return ldb_msg_find_attr_as_string(res[0], attr_name, NULL);
117 }
118
119 /*
120   search the sam for a single string attribute in exactly 1 record
121 */
122 const char *samdb_search_string(struct ldb_context *sam_ldb,
123                                 TALLOC_CTX *mem_ctx,
124                                 struct ldb_dn *basedn,
125                                 const char *attr_name,
126                                 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
127 {
128         va_list ap;
129         const char *str;
130
131         va_start(ap, format);
132         str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
133         va_end(ap);
134
135         return str;
136 }
137
138 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
139                                TALLOC_CTX *mem_ctx,
140                                struct ldb_dn *basedn,
141                                const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
142 {
143         va_list ap;
144         struct ldb_dn *ret;
145         struct ldb_message **res = NULL;
146         int count;
147
148         va_start(ap, format);
149         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
150         va_end(ap);
151
152         if (count != 1) return NULL;
153
154         ret = talloc_steal(mem_ctx, res[0]->dn);
155         talloc_free(res);
156
157         return ret;
158 }
159
160 /*
161   search the sam for a dom_sid attribute in exactly 1 record
162 */
163 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
164                                      TALLOC_CTX *mem_ctx,
165                                      struct ldb_dn *basedn,
166                                      const char *attr_name,
167                                      const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
168 {
169         va_list ap;
170         int count;
171         struct ldb_message **res;
172         const char *attrs[2] = { NULL, NULL };
173         struct dom_sid *sid;
174
175         attrs[0] = attr_name;
176
177         va_start(ap, format);
178         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
179         va_end(ap);
180         if (count > 1) {                
181                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
182                          attr_name, format, count));
183         }
184         if (count != 1) {
185                 talloc_free(res);
186                 return NULL;
187         }
188         sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
189         talloc_free(res);
190         return sid;     
191 }
192
193 /*
194   return the count of the number of records in the sam matching the query
195 */
196 int samdb_search_count(struct ldb_context *sam_ldb,
197                        TALLOC_CTX *mem_ctx,
198                        struct ldb_dn *basedn,
199                        const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
200 {
201         va_list ap;
202         const char *attrs[] = { NULL };
203         int ret;
204
205         va_start(ap, format);
206         ret = gendb_search_v(sam_ldb, mem_ctx, basedn, NULL, attrs, format, ap);
207         va_end(ap);
208
209         return ret;
210 }
211
212
213 /*
214   search the sam for a single integer attribute in exactly 1 record
215 */
216 unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
217                          TALLOC_CTX *mem_ctx,
218                          unsigned int default_value,
219                          struct ldb_dn *basedn,
220                          const char *attr_name,
221                          const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
222 {
223         va_list ap;
224         int count;
225         struct ldb_message **res;
226         const char *attrs[2] = { NULL, NULL };
227
228         attrs[0] = attr_name;
229
230         va_start(ap, format);
231         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
232         va_end(ap);
233
234         if (count != 1) {
235                 return default_value;
236         }
237
238         return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value);
239 }
240
241 /*
242   search the sam for a single signed 64 bit integer attribute in exactly 1 record
243 */
244 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
245                            TALLOC_CTX *mem_ctx,
246                            int64_t default_value,
247                            struct ldb_dn *basedn,
248                            const char *attr_name,
249                            const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
250 {
251         va_list ap;
252         int count;
253         struct ldb_message **res;
254         const char *attrs[2] = { NULL, NULL };
255
256         attrs[0] = attr_name;
257
258         va_start(ap, format);
259         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
260         va_end(ap);
261
262         if (count != 1) {
263                 return default_value;
264         }
265
266         return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value);
267 }
268
269 /*
270   search the sam for multipe records each giving a single string attribute
271   return the number of matches, or -1 on error
272 */
273 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
274                                  TALLOC_CTX *mem_ctx,
275                                  struct ldb_dn *basedn,
276                                  const char ***strs,
277                                  const char *attr_name,
278                                  const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
279 {
280         va_list ap;
281         int count, i;
282         const char *attrs[2] = { NULL, NULL };
283         struct ldb_message **res = NULL;
284
285         attrs[0] = attr_name;
286
287         va_start(ap, format);
288         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
289         va_end(ap);
290
291         if (count <= 0) {
292                 return count;
293         }
294
295         /* make sure its single valued */
296         for (i=0;i<count;i++) {
297                 if (res[i]->num_elements != 1) {
298                         DEBUG(1,("samdb: search for %s %s not single valued\n", 
299                                  attr_name, format));
300                         talloc_free(res);
301                         return -1;
302                 }
303         }
304
305         *strs = talloc_array(mem_ctx, const char *, count+1);
306         if (! *strs) {
307                 talloc_free(res);
308                 return -1;
309         }
310
311         for (i=0;i<count;i++) {
312                 (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL);
313         }
314         (*strs)[count] = NULL;
315
316         return count;
317 }
318
319 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
320                                const char *attr, struct ldb_dn *default_value)
321 {
322         struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
323         if (!ret_dn) {
324                 return default_value;
325         }
326         return ret_dn;
327 }
328
329 /*
330   pull a rid from a objectSid in a result set. 
331 */
332 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
333                                    const char *attr, uint32_t default_value)
334 {
335         struct dom_sid *sid;
336         uint32_t rid;
337
338         sid = samdb_result_dom_sid(mem_ctx, msg, attr);
339         if (sid == NULL) {
340                 return default_value;
341         }
342         rid = sid->sub_auths[sid->num_auths-1];
343         talloc_free(sid);
344         return rid;
345 }
346
347 /*
348   pull a dom_sid structure from a objectSid in a result set. 
349 */
350 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
351                                      const char *attr)
352 {
353         bool ok;
354         const struct ldb_val *v;
355         struct dom_sid *sid;
356         v = ldb_msg_find_ldb_val(msg, attr);
357         if (v == NULL) {
358                 return NULL;
359         }
360         sid = talloc(mem_ctx, struct dom_sid);
361         if (sid == NULL) {
362                 return NULL;
363         }
364         ok = sid_parse(v->data, v->length, sid);
365         if (!ok) {
366                 talloc_free(sid);
367                 return NULL;
368         }
369         return sid;
370 }
371
372 /*
373   pull a guid structure from a objectGUID in a result set. 
374 */
375 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
376 {
377         const struct ldb_val *v;
378         struct GUID guid;
379         NTSTATUS status;
380
381         v = ldb_msg_find_ldb_val(msg, attr);
382         if (!v) return GUID_zero();
383
384         status = GUID_from_ndr_blob(v, &guid);
385         if (!NT_STATUS_IS_OK(status)) {
386                 return GUID_zero();
387         }
388
389         return guid;
390 }
391
392 /*
393   pull a sid prefix from a objectSid in a result set. 
394   this is used to find the domain sid for a user
395 */
396 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
397                                         const char *attr)
398 {
399         struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
400         if (!sid || sid->num_auths < 1) return NULL;
401         sid->num_auths--;
402         return sid;
403 }
404
405 /*
406   pull a NTTIME in a result set. 
407 */
408 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
409                            NTTIME default_value)
410 {
411         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
412 }
413
414 /*
415  * Windows stores 0 for lastLogoff.
416  * But when a MS DC return the lastLogoff (as Logoff Time)
417  * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
418  * cause windows 2008 and newer version to fail for SMB requests
419  */
420 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
421 {
422         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
423
424         if (ret == 0)
425                 ret = 0x7FFFFFFFFFFFFFFFULL;
426
427         return ret;
428 }
429
430 /*
431  * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
432  * indicate an account doesn't expire.
433  *
434  * When Windows initially creates an account, it sets
435  * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF).  However,
436  * when changing from an account having a specific expiration date to
437  * that account never expiring, it sets accountExpires = 0.
438  *
439  * Consolidate that logic here to allow clearer logic for account expiry in
440  * the rest of the code.
441  */
442 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
443 {
444         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
445                                                  0);
446
447         if (ret == 0)
448                 ret = 0x7FFFFFFFFFFFFFFFULL;
449
450         return ret;
451 }
452
453 /*
454   construct the allow_password_change field from the PwdLastSet attribute and the 
455   domain password settings
456 */
457 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb, 
458                                           TALLOC_CTX *mem_ctx, 
459                                           struct ldb_dn *domain_dn, 
460                                           struct ldb_message *msg, 
461                                           const char *attr)
462 {
463         uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0);
464         int64_t minPwdAge;
465
466         if (attr_time == 0) {
467                 return 0;
468         }
469
470         minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
471
472         /* yes, this is a -= not a += as minPwdAge is stored as the negative
473            of the number of 100-nano-seconds */
474         attr_time -= minPwdAge;
475
476         return attr_time;
477 }
478
479 /*
480   pull a samr_Password structutre from a result set. 
481 */
482 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
483 {
484         struct samr_Password *hash = NULL;
485         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
486         if (val && (val->length >= sizeof(hash->hash))) {
487                 hash = talloc(mem_ctx, struct samr_Password);
488                 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
489         }
490         return hash;
491 }
492
493 /*
494   pull an array of samr_Password structures from a result set.
495 */
496 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
497                            const char *attr, struct samr_Password **hashes)
498 {
499         unsigned int count, i;
500         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
501
502         *hashes = NULL;
503         if (!val) {
504                 return 0;
505         }
506         count = val->length / 16;
507         if (count == 0) {
508                 return 0;
509         }
510
511         *hashes = talloc_array(mem_ctx, struct samr_Password, count);
512         if (! *hashes) {
513                 return 0;
514         }
515
516         for (i=0;i<count;i++) {
517                 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
518         }
519
520         return count;
521 }
522
523 NTSTATUS samdb_result_passwords_from_history(TALLOC_CTX *mem_ctx,
524                                              struct loadparm_context *lp_ctx,
525                                              struct ldb_message *msg,
526                                              unsigned int idx,
527                                              struct samr_Password **lm_pwd,
528                                              struct samr_Password **nt_pwd)
529 {
530         struct samr_Password *lmPwdHash, *ntPwdHash;
531
532         if (nt_pwd) {
533                 unsigned int num_nt;
534                 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHistory", &ntPwdHash);
535                 if (num_nt <= idx) {
536                         *nt_pwd = NULL;
537                 } else {
538                         *nt_pwd = &ntPwdHash[idx];
539                 }
540         }
541         if (lm_pwd) {
542                 /* Ensure that if we have turned off LM
543                  * authentication, that we never use the LM hash, even
544                  * if we store it */
545                 if (lpcfg_lanman_auth(lp_ctx)) {
546                         unsigned int num_lm;
547                         num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHistory", &lmPwdHash);
548                         if (num_lm <= idx) {
549                                 *lm_pwd = NULL;
550                         } else {
551                                 *lm_pwd = &lmPwdHash[idx];
552                         }
553                 } else {
554                         *lm_pwd = NULL;
555                 }
556         }
557         return NT_STATUS_OK;
558 }
559
560 NTSTATUS samdb_result_passwords_no_lockout(TALLOC_CTX *mem_ctx,
561                                            struct loadparm_context *lp_ctx,
562                                            const struct ldb_message *msg,
563                                            struct samr_Password **lm_pwd,
564                                            struct samr_Password **nt_pwd)
565 {
566         struct samr_Password *lmPwdHash, *ntPwdHash;
567
568         if (nt_pwd) {
569                 unsigned int num_nt;
570                 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
571                 if (num_nt == 0) {
572                         *nt_pwd = NULL;
573                 } else if (num_nt > 1) {
574                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
575                 } else {
576                         *nt_pwd = &ntPwdHash[0];
577                 }
578         }
579         if (lm_pwd) {
580                 /* Ensure that if we have turned off LM
581                  * authentication, that we never use the LM hash, even
582                  * if we store it */
583                 if (lpcfg_lanman_auth(lp_ctx)) {
584                         unsigned int num_lm;
585                         num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
586                         if (num_lm == 0) {
587                                 *lm_pwd = NULL;
588                         } else if (num_lm > 1) {
589                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
590                         } else {
591                                 *lm_pwd = &lmPwdHash[0];
592                         }
593                 } else {
594                         *lm_pwd = NULL;
595                 }
596         }
597         return NT_STATUS_OK;
598 }
599
600 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx,
601                                 struct loadparm_context *lp_ctx,
602                                 const struct ldb_message *msg,
603                                 struct samr_Password **lm_pwd,
604                                 struct samr_Password **nt_pwd)
605 {
606         uint16_t acct_flags;
607
608         acct_flags = samdb_result_acct_flags(msg,
609                                              "msDS-User-Account-Control-Computed");
610         /* Quit if the account was locked out. */
611         if (acct_flags & ACB_AUTOLOCK) {
612                 DEBUG(3,("samdb_result_passwords: Account for user %s was locked out.\n",
613                          ldb_dn_get_linearized(msg->dn)));
614                 return NT_STATUS_ACCOUNT_LOCKED_OUT;
615         }
616
617         return samdb_result_passwords_no_lockout(mem_ctx, lp_ctx, msg,
618                                                  lm_pwd, nt_pwd);
619 }
620
621 /*
622   pull a samr_LogonHours structutre from a result set. 
623 */
624 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
625 {
626         struct samr_LogonHours hours;
627         size_t units_per_week = 168;
628         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
629
630         ZERO_STRUCT(hours);
631
632         if (val) {
633                 units_per_week = val->length * 8;
634         }
635
636         hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
637         if (!hours.bits) {
638                 return hours;
639         }
640         hours.units_per_week = units_per_week;
641         memset(hours.bits, 0xFF, units_per_week/8);
642         if (val) {
643                 memcpy(hours.bits, val->data, val->length);
644         }
645
646         return hours;
647 }
648
649 /*
650   pull a set of account_flags from a result set. 
651
652   Naturally, this requires that userAccountControl and
653   (if not null) the attributes 'attr' be already
654   included in msg
655 */
656 uint32_t samdb_result_acct_flags(const struct ldb_message *msg, const char *attr)
657 {
658         uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
659         uint32_t attr_flags = 0;
660         uint32_t acct_flags = ds_uf2acb(userAccountControl);
661         if (attr) {
662                 attr_flags = ldb_msg_find_attr_as_uint(msg, attr, UF_ACCOUNTDISABLE);
663                 if (attr_flags == UF_ACCOUNTDISABLE) {
664                         DEBUG(0, ("Attribute %s not found, disabling account %s!\n", attr,
665                                   ldb_dn_get_linearized(msg->dn)));
666                 }
667                 acct_flags |= ds_uf2acb(attr_flags);
668         }
669
670         return acct_flags;
671 }
672
673 NTSTATUS samdb_result_parameters(TALLOC_CTX *mem_ctx,
674                                  struct ldb_message *msg,
675                                  const char *attr,
676                                  struct lsa_BinaryString *s)
677 {
678         int i;
679         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
680
681         ZERO_STRUCTP(s);
682
683         if (!val) {
684                 return NT_STATUS_OK;
685         }
686
687         if ((val->length % 2) != 0) {
688                 /*
689                  * If the on-disk data is not even in length, we know
690                  * it is corrupt, and can not be safely pushed.  We
691                  * would either truncate, send either a un-initilaised
692                  * byte or send a forced zero byte
693                  */
694                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
695         }
696
697         s->array = talloc_array(mem_ctx, uint16_t, val->length/2);
698         if (!s->array) {
699                 return NT_STATUS_NO_MEMORY;
700         }
701         s->length = s->size = val->length;
702
703         /* The on-disk format is the 'network' format, being UTF16LE (sort of) */
704         for (i = 0; i < s->length / 2; i++) {
705                 s->array[i] = SVAL(val->data, i * 2);
706         }
707
708         return NT_STATUS_OK;
709 }
710
711 /* Find an attribute, with a particular value */
712
713 /* The current callers of this function expect a very specific
714  * behaviour: In particular, objectClass subclass equivilance is not
715  * wanted.  This means that we should not lookup the schema for the
716  * comparison function */
717 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb, 
718                                                  const struct ldb_message *msg, 
719                                                  const char *name, const char *value)
720 {
721         unsigned int i;
722         struct ldb_message_element *el = ldb_msg_find_element(msg, name);
723
724         if (!el) {
725                 return NULL;
726         }
727
728         for (i=0;i<el->num_values;i++) {
729                 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
730                         return el;
731                 }
732         }
733
734         return NULL;
735 }
736
737 static int samdb_find_or_add_attribute_ex(struct ldb_context *ldb,
738                                           struct ldb_message *msg,
739                                           const char *name,
740                                           const char *set_value,
741                                           bool *added)
742 {
743         int ret;
744         struct ldb_message_element *el;
745
746         el = ldb_msg_find_element(msg, name);
747         if (el) {
748                 if (added != NULL) {
749                         *added = false;
750                 }
751
752                 return LDB_SUCCESS;
753         }
754
755         ret = ldb_msg_add_string(msg, name, set_value);
756         if (ret != LDB_SUCCESS) {
757                 return ret;
758         }
759         msg->elements[msg->num_elements - 1].flags = LDB_FLAG_MOD_ADD;
760         if (added != NULL) {
761                 *added = true;
762         }
763         return LDB_SUCCESS;
764 }
765
766 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
767 {
768         return samdb_find_or_add_attribute_ex(ldb, msg, name, set_value, NULL);
769 }
770
771 /*
772   add a dom_sid element to a message
773 */
774 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
775                           const char *attr_name, const struct dom_sid *sid)
776 {
777         struct ldb_val v;
778         enum ndr_err_code ndr_err;
779
780         ndr_err = ndr_push_struct_blob(&v, mem_ctx, 
781                                        sid,
782                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
783         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
784                 return ldb_operr(sam_ldb);
785         }
786         return ldb_msg_add_value(msg, attr_name, &v, NULL);
787 }
788
789
790 /*
791   add a delete element operation to a message
792 */
793 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
794                          const char *attr_name)
795 {
796         /* we use an empty replace rather than a delete, as it allows for 
797            dsdb_replace() to be used everywhere */
798         return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
799 }
800
801 /*
802   add an add attribute value to a message or enhance an existing attribute
803   which has the same name and the add flag set.
804 */
805 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
806                          struct ldb_message *msg, const char *attr_name,
807                          const char *value)
808 {
809         struct ldb_message_element *el;
810         struct ldb_val val, *vals;
811         char *v;
812         unsigned int i;
813         bool found = false;
814         int ret;
815
816         v = talloc_strdup(mem_ctx, value);
817         if (v == NULL) {
818                 return ldb_oom(sam_ldb);
819         }
820
821         val.data = (uint8_t *) v;
822         val.length = strlen(v);
823
824         if (val.length == 0) {
825                 /* allow empty strings as non-existent attributes */
826                 return LDB_SUCCESS;
827         }
828
829         for (i = 0; i < msg->num_elements; i++) {
830                 el = &msg->elements[i];
831                 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
832                     (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
833                         found = true;
834                         break;
835                 }
836         }
837         if (!found) {
838                 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
839                                         &el);
840                 if (ret != LDB_SUCCESS) {
841                         return ret;
842                 }
843         }
844
845         vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
846                               el->num_values + 1);
847         if (vals == NULL) {
848                 return ldb_oom(sam_ldb);
849         }
850         el->values = vals;
851         el->values[el->num_values] = val;
852         ++(el->num_values);
853
854         return LDB_SUCCESS;
855 }
856
857 /*
858   add a delete attribute value to a message or enhance an existing attribute
859   which has the same name and the delete flag set.
860 */
861 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
862                          struct ldb_message *msg, const char *attr_name,
863                          const char *value)
864 {
865         struct ldb_message_element *el;
866         struct ldb_val val, *vals;
867         char *v;
868         unsigned int i;
869         bool found = false;
870         int ret;
871
872         v = talloc_strdup(mem_ctx, value);
873         if (v == NULL) {
874                 return ldb_oom(sam_ldb);
875         }
876
877         val.data = (uint8_t *) v;
878         val.length = strlen(v);
879
880         if (val.length == 0) {
881                 /* allow empty strings as non-existent attributes */
882                 return LDB_SUCCESS;
883         }
884
885         for (i = 0; i < msg->num_elements; i++) {
886                 el = &msg->elements[i];
887                 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
888                     (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
889                         found = true;
890                         break;
891                 }
892         }
893         if (!found) {
894                 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
895                                         &el);
896                 if (ret != LDB_SUCCESS) {
897                         return ret;
898                 }
899         }
900
901         vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
902                               el->num_values + 1);
903         if (vals == NULL) {
904                 return ldb_oom(sam_ldb);
905         }
906         el->values = vals;
907         el->values[el->num_values] = val;
908         ++(el->num_values);
909
910         return LDB_SUCCESS;
911 }
912
913 /*
914   add a int element to a message
915 */
916 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
917                        const char *attr_name, int v)
918 {
919         const char *s = talloc_asprintf(mem_ctx, "%d", v);
920         if (s == NULL) {
921                 return ldb_oom(sam_ldb);
922         }
923         return ldb_msg_add_string(msg, attr_name, s);
924 }
925
926 /*
927  * Add an unsigned int element to a message
928  *
929  * The issue here is that we have not yet first cast to int32_t explicitly,
930  * before we cast to an signed int to printf() into the %d or cast to a
931  * int64_t before we then cast to a long long to printf into a %lld.
932  *
933  * There are *no* unsigned integers in Active Directory LDAP, even the RID
934  * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
935  * (See the schema, and the syntax definitions in schema_syntax.c).
936  *
937  */
938 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
939                        const char *attr_name, unsigned int v)
940 {
941         return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
942 }
943
944 /*
945   add a (signed) int64_t element to a message
946 */
947 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
948                         const char *attr_name, int64_t v)
949 {
950         const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
951         if (s == NULL) {
952                 return ldb_oom(sam_ldb);
953         }
954         return ldb_msg_add_string(msg, attr_name, s);
955 }
956
957 /*
958  * Add an unsigned int64_t (uint64_t) element to a message
959  *
960  * The issue here is that we have not yet first cast to int32_t explicitly,
961  * before we cast to an signed int to printf() into the %d or cast to a
962  * int64_t before we then cast to a long long to printf into a %lld.
963  *
964  * There are *no* unsigned integers in Active Directory LDAP, even the RID
965  * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
966  * (See the schema, and the syntax definitions in schema_syntax.c).
967  *
968  */
969 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
970                         const char *attr_name, uint64_t v)
971 {
972         return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
973 }
974
975 /*
976   add a samr_Password element to a message
977 */
978 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
979                        const char *attr_name, const struct samr_Password *hash)
980 {
981         struct ldb_val val;
982         val.data = talloc_memdup(mem_ctx, hash->hash, 16);
983         if (!val.data) {
984                 return ldb_oom(sam_ldb);
985         }
986         val.length = 16;
987         return ldb_msg_add_value(msg, attr_name, &val, NULL);
988 }
989
990 /*
991   add a samr_Password array to a message
992 */
993 int samdb_msg_add_hashes(struct ldb_context *ldb,
994                          TALLOC_CTX *mem_ctx, struct ldb_message *msg,
995                          const char *attr_name, struct samr_Password *hashes,
996                          unsigned int count)
997 {
998         struct ldb_val val;
999         unsigned int i;
1000         val.data = talloc_array_size(mem_ctx, 16, count);
1001         val.length = count*16;
1002         if (!val.data) {
1003                 return ldb_oom(ldb);
1004         }
1005         for (i=0;i<count;i++) {
1006                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
1007         }
1008         return ldb_msg_add_value(msg, attr_name, &val, NULL);
1009 }
1010
1011 /*
1012   add a acct_flags element to a message
1013 */
1014 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1015                              const char *attr_name, uint32_t v)
1016 {
1017         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1018 }
1019
1020 /*
1021   add a logon_hours element to a message
1022 */
1023 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1024                               const char *attr_name, struct samr_LogonHours *hours)
1025 {
1026         struct ldb_val val;
1027         val.length = hours->units_per_week / 8;
1028         val.data = hours->bits;
1029         return ldb_msg_add_value(msg, attr_name, &val, NULL);
1030 }
1031
1032 /*
1033   add a parameters element to a message
1034 */
1035 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1036                              const char *attr_name, struct lsa_BinaryString *parameters)
1037 {
1038         int i;
1039         struct ldb_val val;
1040         if ((parameters->length % 2) != 0) {
1041                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1042         }
1043
1044         val.data = talloc_array(mem_ctx, uint8_t, parameters->length);
1045         if (val.data == NULL) {
1046                 return LDB_ERR_OPERATIONS_ERROR;
1047         }
1048         val.length = parameters->length;
1049         for (i = 0; i < parameters->length / 2; i++) {
1050                 /*
1051                  * The on-disk format needs to be in the 'network'
1052                  * format, parmeters->array is a uint16_t array of
1053                  * length parameters->length / 2
1054                  */
1055                 SSVAL(val.data, i * 2, parameters->array[i]);
1056         }
1057         return ldb_msg_add_steal_value(msg, attr_name, &val);
1058 }
1059
1060 /*
1061  * Sets an unsigned int element in a message
1062  *
1063  * The issue here is that we have not yet first cast to int32_t explicitly,
1064  * before we cast to an signed int to printf() into the %d or cast to a
1065  * int64_t before we then cast to a long long to printf into a %lld.
1066  *
1067  * There are *no* unsigned integers in Active Directory LDAP, even the RID
1068  * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
1069  * (See the schema, and the syntax definitions in schema_syntax.c).
1070  *
1071  */
1072 int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1073                        struct ldb_message *msg, const char *attr_name,
1074                        unsigned int v)
1075 {
1076         struct ldb_message_element *el;
1077
1078         el = ldb_msg_find_element(msg, attr_name);
1079         if (el) {
1080                 el->num_values = 0;
1081         }
1082         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
1083 }
1084
1085 /*
1086  * Handle ldb_request in transaction
1087  */
1088 int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1089                                  struct ldb_request *req)
1090 {
1091         int ret;
1092
1093         ret = ldb_transaction_start(sam_ldb);
1094         if (ret != LDB_SUCCESS) {
1095                 return ret;
1096         }
1097
1098         ret = ldb_request(sam_ldb, req);
1099         if (ret == LDB_SUCCESS) {
1100                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1101         }
1102
1103         if (ret == LDB_SUCCESS) {
1104                 return ldb_transaction_commit(sam_ldb);
1105         }
1106         ldb_transaction_cancel(sam_ldb);
1107
1108         return ret;
1109 }
1110
1111 /*
1112   return a default security descriptor
1113 */
1114 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1115 {
1116         struct security_descriptor *sd;
1117
1118         sd = security_descriptor_initialise(mem_ctx);
1119
1120         return sd;
1121 }
1122
1123 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) 
1124 {
1125         struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1126         struct ldb_dn *aggregate_dn;
1127         if (!schema_dn) {
1128                 return NULL;
1129         }
1130
1131         aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1132         if (!aggregate_dn) {
1133                 return NULL;
1134         }
1135         if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1136                 return NULL;
1137         }
1138         return aggregate_dn;
1139 }
1140
1141 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1142 {
1143         struct ldb_dn *new_dn;
1144
1145         new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1146         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1147                 talloc_free(new_dn);
1148                 return NULL;
1149         }
1150         return new_dn;
1151 }
1152
1153 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1154 {
1155        struct ldb_dn *new_dn;
1156
1157        new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1158        if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1159                talloc_free(new_dn);
1160                return NULL;
1161        }
1162        return new_dn;
1163 }
1164
1165 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1166 {
1167         struct ldb_dn *new_dn;
1168
1169         new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1170         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1171                 talloc_free(new_dn);
1172                 return NULL;
1173         }
1174         return new_dn;
1175 }
1176
1177 /*
1178   work out the domain sid for the current open ldb
1179 */
1180 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1181 {
1182         TALLOC_CTX *tmp_ctx;
1183         const struct dom_sid *domain_sid;
1184         const char *attrs[] = {
1185                 "objectSid",
1186                 NULL
1187         };
1188         struct ldb_result *res;
1189         int ret;
1190
1191         /* see if we have a cached copy */
1192         domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1193         if (domain_sid) {
1194                 return domain_sid;
1195         }
1196
1197         tmp_ctx = talloc_new(ldb);
1198         if (tmp_ctx == NULL) {
1199                 goto failed;
1200         }
1201
1202         ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1203
1204         if (ret != LDB_SUCCESS) {
1205                 goto failed;
1206         }
1207
1208         if (res->count != 1) {
1209                 goto failed;
1210         }
1211
1212         domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1213         if (domain_sid == NULL) {
1214                 goto failed;
1215         }
1216
1217         /* cache the domain_sid in the ldb */
1218         if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1219                 goto failed;
1220         }
1221
1222         talloc_steal(ldb, domain_sid);
1223         talloc_free(tmp_ctx);
1224
1225         return domain_sid;
1226
1227 failed:
1228         talloc_free(tmp_ctx);
1229         return NULL;
1230 }
1231
1232 /*
1233   get domain sid from cache
1234 */
1235 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1236 {
1237         return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1238 }
1239
1240 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1241 {
1242         TALLOC_CTX *tmp_ctx;
1243         struct dom_sid *dom_sid_new;
1244         struct dom_sid *dom_sid_old;
1245
1246         /* see if we have a cached copy */
1247         dom_sid_old = talloc_get_type(ldb_get_opaque(ldb, 
1248                                                      "cache.domain_sid"), struct dom_sid);
1249
1250         tmp_ctx = talloc_new(ldb);
1251         if (tmp_ctx == NULL) {
1252                 goto failed;
1253         }
1254
1255         dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1256         if (!dom_sid_new) {
1257                 goto failed;
1258         }
1259
1260         /* cache the domain_sid in the ldb */
1261         if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1262                 goto failed;
1263         }
1264
1265         talloc_steal(ldb, dom_sid_new);
1266         talloc_free(tmp_ctx);
1267         talloc_free(dom_sid_old);
1268
1269         return true;
1270
1271 failed:
1272         DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1273         talloc_free(tmp_ctx);
1274         return false;
1275 }
1276
1277 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1278 {
1279         TALLOC_CTX *tmp_ctx;
1280         struct ldb_dn *ntds_settings_dn_new;
1281         struct ldb_dn *ntds_settings_dn_old;
1282
1283         /* see if we have a forced copy from provision */
1284         ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb, 
1285                                                               "forced.ntds_settings_dn"), struct ldb_dn);
1286
1287         tmp_ctx = talloc_new(ldb);
1288         if (tmp_ctx == NULL) {
1289                 goto failed;
1290         }
1291
1292         ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1293         if (!ntds_settings_dn_new) {
1294                 goto failed;
1295         }
1296
1297         /* set the DN in the ldb to avoid lookups during provision */
1298         if (ldb_set_opaque(ldb, "forced.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1299                 goto failed;
1300         }
1301
1302         talloc_steal(ldb, ntds_settings_dn_new);
1303         talloc_free(tmp_ctx);
1304         talloc_free(ntds_settings_dn_old);
1305
1306         return true;
1307
1308 failed:
1309         DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1310         talloc_free(tmp_ctx);
1311         return false;
1312 }
1313
1314 /*
1315   work out the ntds settings dn for the current open ldb
1316 */
1317 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1318 {
1319         TALLOC_CTX *tmp_ctx;
1320         const char *root_attrs[] = { "dsServiceName", NULL };
1321         int ret;
1322         struct ldb_result *root_res;
1323         struct ldb_dn *settings_dn;
1324
1325         /* see if we have a cached copy */
1326         settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "forced.ntds_settings_dn");
1327         if (settings_dn) {
1328                 return ldb_dn_copy(mem_ctx, settings_dn);
1329         }
1330
1331         tmp_ctx = talloc_new(mem_ctx);
1332         if (tmp_ctx == NULL) {
1333                 goto failed;
1334         }
1335
1336         ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1337         if (ret != LDB_SUCCESS) {
1338                 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n", 
1339                          ldb_errstring(ldb)));
1340                 goto failed;
1341         }
1342
1343         if (root_res->count != 1) {
1344                 goto failed;
1345         }
1346
1347         settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1348
1349         /* note that we do not cache the DN here, as that would mean
1350          * we could not handle server renames at runtime. Only
1351          * provision sets up forced.ntds_settings_dn */
1352
1353         talloc_steal(mem_ctx, settings_dn);
1354         talloc_free(tmp_ctx);
1355
1356         return settings_dn;
1357
1358 failed:
1359         DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1360         talloc_free(tmp_ctx);
1361         return NULL;
1362 }
1363
1364 /*
1365   work out the ntds settings invocationId for the current open ldb
1366 */
1367 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1368 {
1369         TALLOC_CTX *tmp_ctx;
1370         const char *attrs[] = { "invocationId", NULL };
1371         int ret;
1372         struct ldb_result *res;
1373         struct GUID *invocation_id;
1374
1375         /* see if we have a cached copy */
1376         invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1377         if (invocation_id) {
1378                 SMB_ASSERT(!GUID_all_zero(invocation_id));
1379                 return invocation_id;
1380         }
1381
1382         tmp_ctx = talloc_new(ldb);
1383         if (tmp_ctx == NULL) {
1384                 goto failed;
1385         }
1386
1387         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
1388         if (ret) {
1389                 goto failed;
1390         }
1391
1392         if (res->count != 1) {
1393                 goto failed;
1394         }
1395
1396         invocation_id = talloc(tmp_ctx, struct GUID);
1397         if (!invocation_id) {
1398                 goto failed;
1399         }
1400
1401         *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1402         if (GUID_all_zero(invocation_id)) {
1403                 if (ldb_msg_find_ldb_val(res->msgs[0], "invocationId")) {
1404                         DEBUG(0, ("Failed to find our own NTDS Settings invocationId in the ldb!\n"));  
1405                 } else {
1406                         DEBUG(0, ("Failed to find parse own NTDS Settings invocationId from the ldb!\n"));
1407                 }
1408                 goto failed;
1409         }
1410
1411         /* cache the domain_sid in the ldb */
1412         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1413                 goto failed;
1414         }
1415
1416         talloc_steal(ldb, invocation_id);
1417         talloc_free(tmp_ctx);
1418
1419         return invocation_id;
1420
1421 failed:
1422         DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1423         talloc_free(tmp_ctx);
1424         return NULL;
1425 }
1426
1427 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1428 {
1429         TALLOC_CTX *tmp_ctx;
1430         struct GUID *invocation_id_new;
1431         struct GUID *invocation_id_old;
1432
1433         /* see if we have a cached copy */
1434         invocation_id_old = (struct GUID *)ldb_get_opaque(ldb, 
1435                                                          "cache.invocation_id");
1436
1437         tmp_ctx = talloc_new(ldb);
1438         if (tmp_ctx == NULL) {
1439                 goto failed;
1440         }
1441
1442         invocation_id_new = talloc(tmp_ctx, struct GUID);
1443         if (!invocation_id_new) {
1444                 goto failed;
1445         }
1446
1447         SMB_ASSERT(!GUID_all_zero(invocation_id_in));
1448         *invocation_id_new = *invocation_id_in;
1449
1450         /* cache the domain_sid in the ldb */
1451         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1452                 goto failed;
1453         }
1454
1455         talloc_steal(ldb, invocation_id_new);
1456         talloc_free(tmp_ctx);
1457         talloc_free(invocation_id_old);
1458
1459         return true;
1460
1461 failed:
1462         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1463         talloc_free(tmp_ctx);
1464         return false;
1465 }
1466
1467 /*
1468   work out the ntds settings objectGUID for the current open ldb
1469 */
1470 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1471 {
1472         TALLOC_CTX *tmp_ctx;
1473         const char *attrs[] = { "objectGUID", NULL };
1474         int ret;
1475         struct ldb_result *res;
1476         struct GUID *ntds_guid;
1477
1478         /* see if we have a cached copy */
1479         ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1480         if (ntds_guid) {
1481                 return ntds_guid;
1482         }
1483
1484         tmp_ctx = talloc_new(ldb);
1485         if (tmp_ctx == NULL) {
1486                 goto failed;
1487         }
1488
1489         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
1490         if (ret) {
1491                 goto failed;
1492         }
1493
1494         if (res->count != 1) {
1495                 goto failed;
1496         }
1497
1498         ntds_guid = talloc(tmp_ctx, struct GUID);
1499         if (!ntds_guid) {
1500                 goto failed;
1501         }
1502
1503         *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1504
1505         /* cache the domain_sid in the ldb */
1506         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1507                 goto failed;
1508         }
1509
1510         talloc_steal(ldb, ntds_guid);
1511         talloc_free(tmp_ctx);
1512
1513         return ntds_guid;
1514
1515 failed:
1516         DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1517         talloc_free(tmp_ctx);
1518         return NULL;
1519 }
1520
1521 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1522 {
1523         TALLOC_CTX *tmp_ctx;
1524         struct GUID *ntds_guid_new;
1525         struct GUID *ntds_guid_old;
1526
1527         /* see if we have a cached copy */
1528         ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1529
1530         tmp_ctx = talloc_new(ldb);
1531         if (tmp_ctx == NULL) {
1532                 goto failed;
1533         }
1534
1535         ntds_guid_new = talloc(tmp_ctx, struct GUID);
1536         if (!ntds_guid_new) {
1537                 goto failed;
1538         }
1539
1540         *ntds_guid_new = *ntds_guid_in;
1541
1542         /* cache the domain_sid in the ldb */
1543         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1544                 goto failed;
1545         }
1546
1547         talloc_steal(ldb, ntds_guid_new);
1548         talloc_free(tmp_ctx);
1549         talloc_free(ntds_guid_old);
1550
1551         return true;
1552
1553 failed:
1554         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1555         talloc_free(tmp_ctx);
1556         return false;
1557 }
1558
1559 /*
1560   work out the server dn for the current open ldb
1561 */
1562 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1563 {
1564         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1565         struct ldb_dn *dn;
1566         if (!tmp_ctx) {
1567                 return NULL;
1568         }
1569         dn = ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb, tmp_ctx));
1570         talloc_free(tmp_ctx);
1571         return dn;
1572         
1573 }
1574
1575 /*
1576   work out the server dn for the current open ldb
1577 */
1578 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1579 {
1580         struct ldb_dn *server_dn;
1581         struct ldb_dn *servers_dn;
1582         struct ldb_dn *server_site_dn;
1583
1584         /* TODO: there must be a saner way to do this!! */
1585         server_dn = samdb_server_dn(ldb, mem_ctx);
1586         if (!server_dn) return NULL;
1587
1588         servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1589         talloc_free(server_dn);
1590         if (!servers_dn) return NULL;
1591
1592         server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1593         talloc_free(servers_dn);
1594
1595         return server_site_dn;
1596 }
1597
1598 /*
1599   find the site name from a computers DN record
1600  */
1601 int samdb_find_site_for_computer(struct ldb_context *ldb,
1602                                  TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1603                                  const char **site_name)
1604 {
1605         int ret;
1606         struct ldb_dn *dn;
1607         const struct ldb_val *rdn_val;
1608
1609         *site_name = NULL;
1610
1611         ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1612         if (ret != LDB_SUCCESS) {
1613                 return ret;
1614         }
1615
1616         if (!ldb_dn_remove_child_components(dn, 2)) {
1617                 talloc_free(dn);
1618                 return LDB_ERR_INVALID_DN_SYNTAX;
1619         }
1620
1621         rdn_val = ldb_dn_get_rdn_val(dn);
1622         if (rdn_val == NULL) {
1623                 return LDB_ERR_OPERATIONS_ERROR;
1624         }
1625
1626         (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1627         talloc_free(dn);
1628         if (!*site_name) {
1629                 return LDB_ERR_OPERATIONS_ERROR;
1630         }
1631         return LDB_SUCCESS;
1632 }
1633
1634 /*
1635   find the NTDS GUID from a computers DN record
1636  */
1637 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1638                                      struct GUID *ntds_guid)
1639 {
1640         int ret;
1641         struct ldb_dn *dn;
1642
1643         *ntds_guid = GUID_zero();
1644
1645         ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1646         if (ret != LDB_SUCCESS) {
1647                 return ret;
1648         }
1649
1650         if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1651                 talloc_free(dn);
1652                 return LDB_ERR_OPERATIONS_ERROR;
1653         }
1654
1655         ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1656         talloc_free(dn);
1657         return ret;
1658 }
1659
1660 /*
1661   find a 'reference' DN that points at another object
1662   (eg. serverReference, rIDManagerReference etc)
1663  */
1664 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1665                        const char *attribute, struct ldb_dn **dn)
1666 {
1667         const char *attrs[2];
1668         struct ldb_result *res;
1669         int ret;
1670
1671         attrs[0] = attribute;
1672         attrs[1] = NULL;
1673
1674         ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY|DSDB_SEARCH_SHOW_EXTENDED_DN, NULL);
1675         if (ret != LDB_SUCCESS) {
1676                 ldb_asprintf_errstring(ldb, "Cannot find DN %s to get attribute %s for reference dn: %s",
1677                                        ldb_dn_get_linearized(base), attribute, ldb_errstring(ldb));
1678                 return ret;
1679         }
1680
1681         *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1682         if (!*dn) {
1683                 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1684                         ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1685                                                ldb_dn_get_linearized(base));
1686                 } else {
1687                         ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1688                                                ldb_dn_get_linearized(base));
1689                 }
1690                 talloc_free(res);
1691                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1692         }
1693
1694         talloc_free(res);
1695         return LDB_SUCCESS;
1696 }
1697
1698 /*
1699   find if a DN (must have GUID component!) is our ntdsDsa
1700  */
1701 int samdb_dn_is_our_ntdsa(struct ldb_context *ldb, struct ldb_dn *dn, bool *is_ntdsa)
1702 {
1703         NTSTATUS status;
1704         struct GUID dn_guid;
1705         const struct GUID *our_ntds_guid;
1706         status = dsdb_get_extended_dn_guid(dn, &dn_guid, "GUID");
1707         if (!NT_STATUS_IS_OK(status)) {
1708                 return LDB_ERR_OPERATIONS_ERROR;
1709         }
1710
1711         our_ntds_guid = samdb_ntds_objectGUID(ldb);
1712         if (!our_ntds_guid) {
1713                 DEBUG(0, ("Failed to find our NTDS Settings GUID for comparison with %s - %s\n", ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
1714                 return LDB_ERR_OPERATIONS_ERROR;
1715         }
1716
1717         *is_ntdsa = GUID_equal(&dn_guid, our_ntds_guid);
1718         return LDB_SUCCESS;
1719 }
1720
1721 /*
1722   find a 'reference' DN that points at another object and indicate if it is our ntdsDsa
1723  */
1724 int samdb_reference_dn_is_our_ntdsa(struct ldb_context *ldb, struct ldb_dn *base,
1725                                     const char *attribute, bool *is_ntdsa)
1726 {
1727         int ret;
1728         struct ldb_dn *referenced_dn;
1729         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
1730         if (tmp_ctx == NULL) {
1731                 return LDB_ERR_OPERATIONS_ERROR;
1732         }
1733         ret = samdb_reference_dn(ldb, tmp_ctx, base, attribute, &referenced_dn);
1734         if (ret != LDB_SUCCESS) {
1735                 DEBUG(0, ("Failed to find object %s for attribute %s - %s\n", ldb_dn_get_linearized(base), attribute, ldb_errstring(ldb)));
1736                 return ret;
1737         }
1738
1739         ret = samdb_dn_is_our_ntdsa(ldb, referenced_dn, is_ntdsa);
1740         
1741         talloc_free(tmp_ctx);
1742         return ret;
1743 }
1744
1745 /*
1746   find our machine account via the serverReference attribute in the
1747   server DN
1748  */
1749 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1750 {
1751         struct ldb_dn *server_dn;
1752         int ret;
1753
1754         server_dn = samdb_server_dn(ldb, mem_ctx);
1755         if (server_dn == NULL) {
1756                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
1757         }
1758
1759         ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1760         talloc_free(server_dn);
1761
1762         return ret;
1763 }
1764
1765 /*
1766   find the RID Manager$ DN via the rIDManagerReference attribute in the
1767   base DN
1768  */
1769 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1770 {
1771         return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1772                                   "rIDManagerReference", dn);
1773 }
1774
1775 /*
1776   find the RID Set DN via the rIDSetReferences attribute in our
1777   machine account DN
1778  */
1779 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1780 {
1781         struct ldb_dn *server_ref_dn;
1782         int ret;
1783
1784         ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1785         if (ret != LDB_SUCCESS) {
1786                 return ret;
1787         }
1788         ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1789         talloc_free(server_ref_dn);
1790         return ret;
1791 }
1792
1793 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1794 {
1795         const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1796                                                                             mem_ctx));
1797
1798         if (val == NULL) {
1799                 return NULL;
1800         }
1801
1802         return (const char *) val->data;
1803 }
1804
1805 /*
1806  * Finds the client site by using the client's IP address.
1807  * The "subnet_name" returns the name of the subnet if parameter != NULL
1808  */
1809 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1810                                    const char *ip_address, char **subnet_name)
1811 {
1812         const char *attrs[] = { "cn", "siteObject", NULL };
1813         struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1814         struct ldb_result *res;
1815         const struct ldb_val *val;
1816         const char *site_name = NULL, *l_subnet_name = NULL;
1817         const char *allow_list[2] = { NULL, NULL };
1818         unsigned int i, count;
1819         int cnt, ret;
1820
1821         /*
1822          * if we don't have a client ip e.g. ncalrpc
1823          * the server site is the client site
1824          */
1825         if (ip_address == NULL) {
1826                 return samdb_server_site_name(ldb, mem_ctx);
1827         }
1828
1829         sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1830         if (sites_container_dn == NULL) {
1831                 return NULL;
1832         }
1833
1834         subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1835         if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1836                 talloc_free(sites_container_dn);
1837                 talloc_free(subnets_dn);
1838                 return NULL;
1839         }
1840
1841         ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1842                          attrs, NULL);
1843         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1844                 count = 0;
1845         } else if (ret != LDB_SUCCESS) {
1846                 talloc_free(sites_container_dn);
1847                 talloc_free(subnets_dn);
1848                 return NULL;
1849         } else {
1850                 count = res->count;
1851         }
1852
1853         for (i = 0; i < count; i++) {
1854                 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1855                                                             NULL);
1856
1857                 allow_list[0] = l_subnet_name;
1858
1859                 if (socket_allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1860                         sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1861                                                            res->msgs[i],
1862                                                            "siteObject");
1863                         if (sites_dn == NULL) {
1864                                 /* No reference, maybe another subnet matches */
1865                                 continue;
1866                         }
1867
1868                         /* "val" cannot be NULL here since "sites_dn" != NULL */
1869                         val = ldb_dn_get_rdn_val(sites_dn);
1870                         site_name = talloc_strdup(mem_ctx,
1871                                                   (const char *) val->data);
1872
1873                         talloc_free(sites_dn);
1874
1875                         break;
1876                 }
1877         }
1878
1879         if (site_name == NULL) {
1880                 /* This is the Windows Server fallback rule: when no subnet
1881                  * exists and we have only one site available then use it (it
1882                  * is for sure the same as our server site). If more sites do
1883                  * exist then we don't know which one to use and set the site
1884                  * name to "". */
1885                 cnt = samdb_search_count(ldb, mem_ctx, sites_container_dn,
1886                                          "(objectClass=site)");
1887                 if (cnt == 1) {
1888                         site_name = samdb_server_site_name(ldb, mem_ctx);
1889                 } else {
1890                         site_name = talloc_strdup(mem_ctx, "");
1891                 }
1892                 l_subnet_name = NULL;
1893         }
1894
1895         if (subnet_name != NULL) {
1896                 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1897         }
1898
1899         talloc_free(sites_container_dn);
1900         talloc_free(subnets_dn);
1901         talloc_free(res);
1902
1903         return site_name;
1904 }
1905
1906 /*
1907   work out if we are the PDC for the domain of the current open ldb
1908 */
1909 bool samdb_is_pdc(struct ldb_context *ldb)
1910 {
1911         int ret;
1912         bool is_pdc;
1913
1914         ret = samdb_reference_dn_is_our_ntdsa(ldb, ldb_get_default_basedn(ldb), "fsmoRoleOwner", 
1915                                               &is_pdc);
1916         if (ret != LDB_SUCCESS) {
1917                 DEBUG(1,("Failed to find if we are the PDC for this ldb: Searching for fSMORoleOwner in %s failed: %s\n", 
1918                          ldb_dn_get_linearized(ldb_get_default_basedn(ldb)), 
1919                          ldb_errstring(ldb)));
1920                 return false;
1921         }
1922
1923         return is_pdc;
1924 }
1925
1926 /*
1927   work out if we are a Global Catalog server for the domain of the current open ldb
1928 */
1929 bool samdb_is_gc(struct ldb_context *ldb)
1930 {
1931         uint32_t options;
1932         if (samdb_ntds_options(ldb, &options) != LDB_SUCCESS) {
1933                 return false;
1934         }
1935         return (options & DS_NTDSDSA_OPT_IS_GC) != 0;
1936 }
1937
1938 /* Find a domain object in the parents of a particular DN.  */
1939 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1940                                    struct ldb_dn **parent_dn, const char **errstring)
1941 {
1942         TALLOC_CTX *local_ctx;
1943         struct ldb_dn *sdn = dn;
1944         struct ldb_result *res = NULL;
1945         int ret = LDB_SUCCESS;
1946         const char *attrs[] = { NULL };
1947
1948         local_ctx = talloc_new(mem_ctx);
1949         if (local_ctx == NULL) return ldb_oom(ldb);
1950
1951         while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1952                 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1953                                  "(|(objectClass=domain)(objectClass=builtinDomain))");
1954                 if (ret == LDB_SUCCESS) {
1955                         if (res->count == 1) {
1956                                 break;
1957                         }
1958                 } else {
1959                         break;
1960                 }
1961         }
1962
1963         if (ret != LDB_SUCCESS) {
1964                 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1965                                              ldb_dn_get_linearized(dn),
1966                                              ldb_dn_get_linearized(sdn),
1967                                              ldb_errstring(ldb));
1968                 talloc_free(local_ctx);
1969                 return ret;
1970         }
1971         if (res->count != 1) {
1972                 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1973                                              ldb_dn_get_linearized(dn));
1974                 DEBUG(0,(__location__ ": %s\n", *errstring));
1975                 talloc_free(local_ctx);
1976                 return LDB_ERR_CONSTRAINT_VIOLATION;
1977         }
1978
1979         *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1980         talloc_free(local_ctx);
1981         return ret;
1982 }
1983
1984
1985 /*
1986  * Performs checks on a user password (plaintext UNIX format - attribute
1987  * "password"). The remaining parameters have to be extracted from the domain
1988  * object in the AD.
1989  *
1990  * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
1991  */
1992 enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx,
1993                                                 struct loadparm_context *lp_ctx,
1994                                                 const DATA_BLOB *utf8_blob,
1995                                                 const uint32_t pwdProperties,
1996                                                 const uint32_t minPwdLength)
1997 {
1998         const char *utf8_pw = (const char *)utf8_blob->data;
1999         size_t utf8_len = strlen_m(utf8_pw);
2000         char *password_script = NULL;
2001
2002         /* checks if the "minPwdLength" property is satisfied */
2003         if (minPwdLength > utf8_len) {
2004                 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2005         }
2006
2007         /* checks the password complexity */
2008         if (!(pwdProperties & DOMAIN_PASSWORD_COMPLEX)) {
2009                 return SAMR_VALIDATION_STATUS_SUCCESS;
2010         }
2011
2012         if (utf8_len == 0) {
2013                 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2014         }
2015
2016         password_script = lpcfg_check_password_script(lp_ctx, mem_ctx);
2017         if (password_script != NULL && *password_script != '\0') {
2018                 int check_ret = 0;
2019                 int error = 0;
2020                 struct tevent_context *event_ctx = NULL;
2021                 struct tevent_req *req = NULL;
2022                 struct samba_runcmd_state *run_cmd = NULL;
2023                 const char * const cmd[4] = {
2024                         "/bin/sh", "-c",
2025                         password_script,
2026                         NULL
2027                 };
2028
2029                 event_ctx = tevent_context_init(mem_ctx);
2030                 if (event_ctx == NULL) {
2031                         TALLOC_FREE(password_script);
2032                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2033                 }
2034
2035                 req = samba_runcmd_send(mem_ctx, event_ctx,
2036                                         tevent_timeval_current_ofs(0, 10000000),
2037                                         100, 100, cmd, NULL);
2038                 run_cmd = tevent_req_data(req, struct samba_runcmd_state);
2039                 if (write(run_cmd->fd_stdin, utf8_pw, utf8_len) != utf8_len) {
2040                         TALLOC_FREE(password_script);
2041                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2042                 }
2043
2044                 close(run_cmd->fd_stdin);
2045                 run_cmd->fd_stdin = -1;
2046
2047                 if (!tevent_req_poll(req, event_ctx)) {
2048                         TALLOC_FREE(password_script);
2049                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2050                 }
2051
2052                 check_ret = samba_runcmd_recv(req, &error);
2053                 TALLOC_FREE(req);
2054
2055                 DEBUG(5,("check_password_complexity: check password script (%s) "
2056                          "returned [%d]\n", password_script, check_ret));
2057                 TALLOC_FREE(password_script);
2058
2059                 if (check_ret != 0) {
2060                         DEBUG(1,("check_password_complexity: "
2061                                  "check password script said new password is not good "
2062                                  "enough!\n"));
2063                         return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2064                 }
2065
2066                 return SAMR_VALIDATION_STATUS_SUCCESS;
2067         }
2068
2069         TALLOC_FREE(password_script);
2070
2071         if (!check_password_quality(utf8_pw)) {
2072                 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2073         }
2074
2075         return SAMR_VALIDATION_STATUS_SUCCESS;
2076 }
2077
2078 /*
2079  * Callback for "samdb_set_password" password change
2080  */
2081 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2082 {
2083         int ret;
2084
2085         if (!ares) {
2086                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2087         }
2088
2089         if (ares->error != LDB_SUCCESS) {
2090                 ret = ares->error;
2091                 req->context = talloc_steal(req,
2092                                             ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2093                 talloc_free(ares);
2094                 return ldb_request_done(req, ret);
2095         }
2096
2097         if (ares->type != LDB_REPLY_DONE) {
2098                 talloc_free(ares);
2099                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2100         }
2101
2102         req->context = talloc_steal(req,
2103                                     ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2104         talloc_free(ares);
2105         return ldb_request_done(req, LDB_SUCCESS);
2106 }
2107
2108 /*
2109  * Sets the user password using plaintext UTF16 (attribute "new_password") or
2110  * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2111  * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2112  * user change or not. The "rejectReason" gives some more information if the
2113  * change failed.
2114  *
2115  * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2116  *   NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2117  */
2118 static NTSTATUS samdb_set_password_internal(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2119                             struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2120                             const DATA_BLOB *new_password,
2121                             const struct samr_Password *lmNewHash,
2122                             const struct samr_Password *ntNewHash,
2123                             const struct samr_Password *lmOldHash,
2124                             const struct samr_Password *ntOldHash,
2125                             enum samPwdChangeReason *reject_reason,
2126                             struct samr_DomInfo1 **_dominfo,
2127                             bool permit_interdomain_trust)
2128 {
2129         struct ldb_message *msg;
2130         struct ldb_message_element *el;
2131         struct ldb_request *req;
2132         struct dsdb_control_password_change_status *pwd_stat = NULL;
2133         int ret;
2134         bool hash_values = false;
2135         NTSTATUS status = NT_STATUS_OK;
2136
2137 #define CHECK_RET(x) \
2138         if (x != LDB_SUCCESS) { \
2139                 talloc_free(msg); \
2140                 return NT_STATUS_NO_MEMORY; \
2141         }
2142
2143         msg = ldb_msg_new(mem_ctx);
2144         if (msg == NULL) {
2145                 return NT_STATUS_NO_MEMORY;
2146         }
2147         msg->dn = user_dn;
2148         if ((new_password != NULL)
2149                         && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2150                 /* we have the password as plaintext UTF16 */
2151                 CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
2152                                             new_password, NULL));
2153                 el = ldb_msg_find_element(msg, "clearTextPassword");
2154                 el->flags = LDB_FLAG_MOD_REPLACE;
2155         } else if ((new_password == NULL)
2156                         && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2157                 /* we have a password as LM and/or NT hash */
2158                 if (lmNewHash != NULL) {
2159                         CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2160                                 "dBCSPwd", lmNewHash));
2161                         el = ldb_msg_find_element(msg, "dBCSPwd");
2162                         el->flags = LDB_FLAG_MOD_REPLACE;
2163                 }
2164                 if (ntNewHash != NULL) {
2165                         CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2166                                 "unicodePwd", ntNewHash));
2167                         el = ldb_msg_find_element(msg, "unicodePwd");
2168                         el->flags = LDB_FLAG_MOD_REPLACE;
2169                 }
2170                 hash_values = true;
2171         } else {
2172                 /* the password wasn't specified correctly */
2173                 talloc_free(msg);
2174                 return NT_STATUS_INVALID_PARAMETER;
2175         }
2176
2177         /* build modify request */
2178         ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2179                                 samdb_set_password_callback, NULL);
2180         if (ret != LDB_SUCCESS) {
2181                 talloc_free(msg);
2182                 return NT_STATUS_NO_MEMORY;
2183         }
2184
2185         /* A password change operation */
2186         if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2187                 struct dsdb_control_password_change *change;
2188
2189                 change = talloc(req, struct dsdb_control_password_change);
2190                 if (change == NULL) {
2191                         talloc_free(req);
2192                         talloc_free(msg);
2193                         return NT_STATUS_NO_MEMORY;
2194                 }
2195
2196                 change->old_nt_pwd_hash = ntOldHash;
2197                 change->old_lm_pwd_hash = lmOldHash;
2198
2199                 ret = ldb_request_add_control(req,
2200                                               DSDB_CONTROL_PASSWORD_CHANGE_OID,
2201                                               true, change);
2202                 if (ret != LDB_SUCCESS) {
2203                         talloc_free(req);
2204                         talloc_free(msg);
2205                         return NT_STATUS_NO_MEMORY;
2206                 }
2207         }
2208         if (hash_values) {
2209                 ret = ldb_request_add_control(req,
2210                                               DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2211                                               true, NULL);
2212                 if (ret != LDB_SUCCESS) {
2213                         talloc_free(req);
2214                         talloc_free(msg);
2215                         return NT_STATUS_NO_MEMORY;
2216                 }
2217         }
2218         if (permit_interdomain_trust) {
2219                 ret = ldb_request_add_control(req,
2220                                               DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
2221                                               false, NULL);
2222                 if (ret != LDB_SUCCESS) {
2223                         talloc_free(req);
2224                         talloc_free(msg);
2225                         return NT_STATUS_NO_MEMORY;
2226                 }
2227         }
2228         ret = ldb_request_add_control(req,
2229                                       DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2230                                       true, NULL);
2231         if (ret != LDB_SUCCESS) {
2232                 talloc_free(req);
2233                 talloc_free(msg);
2234                 return NT_STATUS_NO_MEMORY;
2235         }
2236
2237         ret = dsdb_autotransaction_request(ldb, req);
2238
2239         if (req->context != NULL) {
2240                 struct ldb_control *control = talloc_get_type_abort(req->context,
2241                                                                     struct ldb_control);
2242                 pwd_stat = talloc_get_type_abort(control->data,
2243                                                  struct dsdb_control_password_change_status);
2244                 talloc_steal(mem_ctx, pwd_stat);
2245         }
2246
2247         talloc_free(req);
2248         talloc_free(msg);
2249
2250         /* Sets the domain info (if requested) */
2251         if (_dominfo != NULL) {
2252                 struct samr_DomInfo1 *dominfo;
2253
2254                 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2255                 if (dominfo == NULL) {
2256                         return NT_STATUS_NO_MEMORY;
2257                 }
2258
2259                 if (pwd_stat != NULL) {
2260                         dominfo->min_password_length     = pwd_stat->domain_data.minPwdLength;
2261                         dominfo->password_properties     = pwd_stat->domain_data.pwdProperties;
2262                         dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2263                         dominfo->max_password_age        = pwd_stat->domain_data.maxPwdAge;
2264                         dominfo->min_password_age        = pwd_stat->domain_data.minPwdAge;
2265                 }
2266
2267                 *_dominfo = dominfo;
2268         }
2269
2270         if (reject_reason != NULL) {
2271                 if (pwd_stat != NULL) {
2272                         *reject_reason = pwd_stat->reject_reason;
2273                 } else {
2274                         *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2275                 }
2276         }
2277
2278         if (pwd_stat != NULL) {
2279                 talloc_free(pwd_stat);
2280         }
2281
2282         if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2283                 const char *errmsg = ldb_errstring(ldb);
2284                 char *endptr = NULL;
2285                 WERROR werr = WERR_GENERAL_FAILURE;
2286                 status = NT_STATUS_UNSUCCESSFUL;
2287                 if (errmsg != NULL) {
2288                         werr = W_ERROR(strtol(errmsg, &endptr, 16));
2289                         DBG_WARNING("%s\n", errmsg);
2290                 }
2291                 if (endptr != errmsg) {
2292                         if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2293                                 status = NT_STATUS_WRONG_PASSWORD;
2294                         }
2295                         if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2296                                 status = NT_STATUS_PASSWORD_RESTRICTION;
2297                         }
2298                 }
2299         } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2300                 /* don't let the caller know if an account doesn't exist */
2301                 status = NT_STATUS_WRONG_PASSWORD;
2302         } else if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2303                 status = NT_STATUS_ACCESS_DENIED;
2304         } else if (ret != LDB_SUCCESS) {
2305                 DEBUG(1, ("Failed to set password on %s: %s\n",
2306                           ldb_dn_get_linearized(msg->dn),
2307                           ldb_errstring(ldb)));
2308                 status = NT_STATUS_UNSUCCESSFUL;
2309         }
2310
2311         return status;
2312 }
2313
2314 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2315                             struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2316                             const DATA_BLOB *new_password,
2317                             const struct samr_Password *lmNewHash,
2318                             const struct samr_Password *ntNewHash,
2319                             const struct samr_Password *lmOldHash,
2320                             const struct samr_Password *ntOldHash,
2321                             enum samPwdChangeReason *reject_reason,
2322                             struct samr_DomInfo1 **_dominfo)
2323 {
2324         return samdb_set_password_internal(ldb, mem_ctx,
2325                             user_dn, domain_dn,
2326                             new_password,
2327                             lmNewHash, ntNewHash,
2328                             lmOldHash, ntOldHash,
2329                             reject_reason, _dominfo,
2330                             false); /* reject trusts */
2331 }
2332
2333 /*
2334  * Sets the user password using plaintext UTF16 (attribute "new_password") or
2335  * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2336  * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2337  * user change or not. The "rejectReason" gives some more information if the
2338  * change failed.
2339  *
2340  * This wrapper function for "samdb_set_password" takes a SID as input rather
2341  * than a user DN.
2342  *
2343  * This call encapsulates a new LDB transaction for changing the password;
2344  * therefore the user hasn't to start a new one.
2345  *
2346  * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2347  *   NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2348  *   NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2349  *   NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2350  */
2351 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2352                                 const struct dom_sid *user_sid,
2353                                 const uint32_t *new_version, /* optional for trusts */
2354                                 const DATA_BLOB *new_password,
2355                                 const struct samr_Password *lmNewHash,
2356                                 const struct samr_Password *ntNewHash,
2357                                 const struct samr_Password *lmOldHash,
2358                                 const struct samr_Password *ntOldHash,
2359                                 enum samPwdChangeReason *reject_reason,
2360                                 struct samr_DomInfo1 **_dominfo) 
2361 {
2362         TALLOC_CTX *frame = talloc_stackframe();
2363         NTSTATUS nt_status;
2364         const char * const user_attrs[] = {
2365                 "userAccountControl",
2366                 "sAMAccountName",
2367                 NULL
2368         };
2369         struct ldb_message *user_msg = NULL;
2370         int ret;
2371         uint32_t uac = 0;
2372
2373         ret = ldb_transaction_start(ldb);
2374         if (ret != LDB_SUCCESS) {
2375                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2376                 TALLOC_FREE(frame);
2377                 return NT_STATUS_TRANSACTION_ABORTED;
2378         }
2379
2380         ret = dsdb_search_one(ldb, frame, &user_msg, ldb_get_default_basedn(ldb),
2381                               LDB_SCOPE_SUBTREE, user_attrs, 0,
2382                               "(&(objectSid=%s)(objectClass=user))",
2383                               ldap_encode_ndr_dom_sid(frame, user_sid));
2384         if (ret != LDB_SUCCESS) {
2385                 ldb_transaction_cancel(ldb);
2386                 DEBUG(3, ("samdb_set_password_sid: SID[%s] not found in samdb %s - %s, "
2387                           "returning NO_SUCH_USER\n",
2388                           dom_sid_string(frame, user_sid),
2389                           ldb_strerror(ret), ldb_errstring(ldb)));
2390                 TALLOC_FREE(frame);
2391                 return NT_STATUS_NO_SUCH_USER;
2392         }
2393
2394         uac = ldb_msg_find_attr_as_uint(user_msg, "userAccountControl", 0);
2395         if (!(uac & UF_ACCOUNT_TYPE_MASK)) {
2396                 ldb_transaction_cancel(ldb);
2397                 DEBUG(1, ("samdb_set_password_sid: invalid "
2398                           "userAccountControl[0x%08X] for SID[%s] DN[%s], "
2399                           "returning NO_SUCH_USER\n",
2400                           (unsigned)uac, dom_sid_string(frame, user_sid),
2401                           ldb_dn_get_linearized(user_msg->dn)));
2402                 TALLOC_FREE(frame);
2403                 return NT_STATUS_NO_SUCH_USER;
2404         }
2405
2406         if (uac & UF_INTERDOMAIN_TRUST_ACCOUNT) {
2407                 const char * const tdo_attrs[] = {
2408                         "trustAuthIncoming",
2409                         "trustDirection",
2410                         NULL
2411                 };
2412                 struct ldb_message *tdo_msg = NULL;
2413                 const char *account_name = NULL;
2414                 uint32_t trust_direction;
2415                 uint32_t i;
2416                 const struct ldb_val *old_val = NULL;
2417                 struct trustAuthInOutBlob old_blob = {};
2418                 uint32_t old_version = 0;
2419                 struct AuthenticationInformation *old_version_a = NULL;
2420                 uint32_t _new_version = 0;
2421                 struct trustAuthInOutBlob new_blob = {};
2422                 struct ldb_val new_val = {};
2423                 struct timeval tv = timeval_current();
2424                 NTTIME now = timeval_to_nttime(&tv);
2425                 enum ndr_err_code ndr_err;
2426
2427                 if (new_password == NULL && ntNewHash == NULL) {
2428                         ldb_transaction_cancel(ldb);
2429                         DEBUG(1, ("samdb_set_password_sid: "
2430                                   "no new password provided "
2431                                   "sAMAccountName for SID[%s] DN[%s], "
2432                                   "returning INVALID_PARAMETER\n",
2433                                   dom_sid_string(frame, user_sid),
2434                                   ldb_dn_get_linearized(user_msg->dn)));
2435                         TALLOC_FREE(frame);
2436                         return NT_STATUS_INVALID_PARAMETER;
2437                 }
2438
2439                 if (new_password != NULL && ntNewHash != NULL) {
2440                         ldb_transaction_cancel(ldb);
2441                         DEBUG(1, ("samdb_set_password_sid: "
2442                                   "two new passwords provided "
2443                                   "sAMAccountName for SID[%s] DN[%s], "
2444                                   "returning INVALID_PARAMETER\n",
2445                                   dom_sid_string(frame, user_sid),
2446                                   ldb_dn_get_linearized(user_msg->dn)));
2447                         TALLOC_FREE(frame);
2448                         return NT_STATUS_INVALID_PARAMETER;
2449                 }
2450
2451                 if (new_password != NULL && (new_password->length % 2)) {
2452                         ldb_transaction_cancel(ldb);
2453                         DEBUG(2, ("samdb_set_password_sid: "
2454                                   "invalid utf16 length (%zu) "
2455                                   "sAMAccountName for SID[%s] DN[%s], "
2456                                   "returning WRONG_PASSWORD\n",
2457                                   new_password->length,
2458                                   dom_sid_string(frame, user_sid),
2459                                   ldb_dn_get_linearized(user_msg->dn)));
2460                         TALLOC_FREE(frame);
2461                         return NT_STATUS_WRONG_PASSWORD;
2462                 }
2463
2464                 if (new_password != NULL && new_password->length >= 500) {
2465                         ldb_transaction_cancel(ldb);
2466                         DEBUG(2, ("samdb_set_password_sid: "
2467                                   "utf16 password too long (%zu) "
2468                                   "sAMAccountName for SID[%s] DN[%s], "
2469                                   "returning WRONG_PASSWORD\n",
2470                                   new_password->length,
2471                                   dom_sid_string(frame, user_sid),
2472                                   ldb_dn_get_linearized(user_msg->dn)));
2473                         TALLOC_FREE(frame);
2474                         return NT_STATUS_WRONG_PASSWORD;
2475                 }
2476
2477                 account_name = ldb_msg_find_attr_as_string(user_msg,
2478                                                         "sAMAccountName", NULL);
2479                 if (account_name == NULL) {
2480                         ldb_transaction_cancel(ldb);
2481                         DEBUG(1, ("samdb_set_password_sid: missing "
2482                                   "sAMAccountName for SID[%s] DN[%s], "
2483                                   "returning NO_SUCH_USER\n",
2484                                   dom_sid_string(frame, user_sid),
2485                                   ldb_dn_get_linearized(user_msg->dn)));
2486                         TALLOC_FREE(frame);
2487                         return NT_STATUS_NO_SUCH_USER;
2488                 }
2489
2490                 nt_status = dsdb_trust_search_tdo_by_type(ldb,
2491                                                           SEC_CHAN_DOMAIN,
2492                                                           account_name,
2493                                                           tdo_attrs,
2494                                                           frame, &tdo_msg);
2495                 if (!NT_STATUS_IS_OK(nt_status)) {
2496                         ldb_transaction_cancel(ldb);
2497                         DEBUG(1, ("samdb_set_password_sid: dsdb_trust_search_tdo "
2498                                   "failed(%s) for sAMAccountName[%s] SID[%s] DN[%s], "
2499                                   "returning INTERNAL_DB_CORRUPTION\n",
2500                                   nt_errstr(nt_status), account_name,
2501                                   dom_sid_string(frame, user_sid),
2502                                   ldb_dn_get_linearized(user_msg->dn)));
2503                         TALLOC_FREE(frame);
2504                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2505                 }
2506
2507                 trust_direction = ldb_msg_find_attr_as_int(tdo_msg,
2508                                                            "trustDirection", 0);
2509                 if (!(trust_direction & LSA_TRUST_DIRECTION_INBOUND)) {
2510                         ldb_transaction_cancel(ldb);
2511                         DEBUG(1, ("samdb_set_password_sid: direction[0x%08X] is "
2512                                   "not inbound for sAMAccountName[%s] "
2513                                   "DN[%s] TDO[%s], "
2514                                   "returning INTERNAL_DB_CORRUPTION\n",
2515                                   (unsigned)trust_direction,
2516                                   account_name,
2517                                   ldb_dn_get_linearized(user_msg->dn),
2518                                   ldb_dn_get_linearized(tdo_msg->dn)));
2519                         TALLOC_FREE(frame);
2520                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2521                 }
2522
2523                 old_val = ldb_msg_find_ldb_val(tdo_msg, "trustAuthIncoming");
2524                 if (old_val != NULL) {
2525                         ndr_err = ndr_pull_struct_blob(old_val, frame, &old_blob,
2526                                         (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
2527                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2528                                 ldb_transaction_cancel(ldb);
2529                                 DEBUG(1, ("samdb_set_password_sid: "
2530                                           "failed(%s) to parse "
2531                                           "trustAuthOutgoing sAMAccountName[%s] "
2532                                           "DN[%s] TDO[%s], "
2533                                           "returning INTERNAL_DB_CORRUPTION\n",
2534                                           ndr_map_error2string(ndr_err),
2535                                           account_name,
2536                                           ldb_dn_get_linearized(user_msg->dn),
2537                                           ldb_dn_get_linearized(tdo_msg->dn)));
2538
2539                                 TALLOC_FREE(frame);
2540                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2541                         }
2542                 }
2543
2544                 for (i = old_blob.current.count; i > 0; i--) {
2545                         struct AuthenticationInformation *a =
2546                                 &old_blob.current.array[i - 1];
2547
2548                         switch (a->AuthType) {
2549                         case TRUST_AUTH_TYPE_NONE:
2550                                 if (i == old_blob.current.count) {
2551                                         /*
2552                                          * remove TRUST_AUTH_TYPE_NONE at the
2553                                          * end
2554                                          */
2555                                         old_blob.current.count--;
2556                                 }
2557                                 break;
2558
2559                         case TRUST_AUTH_TYPE_VERSION:
2560                                 old_version_a = a;
2561                                 old_version = a->AuthInfo.version.version;
2562                                 break;
2563
2564                         case TRUST_AUTH_TYPE_CLEAR:
2565                                 break;
2566
2567                         case TRUST_AUTH_TYPE_NT4OWF:
2568                                 break;
2569                         }
2570                 }
2571
2572                 if (new_version == NULL) {
2573                         _new_version = 0;
2574                         new_version = &_new_version;
2575                 }
2576
2577                 if (old_version_a != NULL && *new_version != (old_version + 1)) {
2578                         old_version_a->LastUpdateTime = now;
2579                         old_version_a->AuthType = TRUST_AUTH_TYPE_NONE;
2580                 }
2581
2582                 new_blob.count = MAX(old_blob.current.count, 2);
2583                 new_blob.current.array = talloc_zero_array(frame,
2584                                                 struct AuthenticationInformation,
2585                                                 new_blob.count);
2586                 if (new_blob.current.array == NULL) {
2587                         ldb_transaction_cancel(ldb);
2588                         TALLOC_FREE(frame);
2589                         return NT_STATUS_NO_MEMORY;
2590                 }
2591                 new_blob.previous.array = talloc_zero_array(frame,
2592                                                 struct AuthenticationInformation,
2593                                                 new_blob.count);
2594                 if (new_blob.current.array == NULL) {
2595                         ldb_transaction_cancel(ldb);
2596                         TALLOC_FREE(frame);
2597                         return NT_STATUS_NO_MEMORY;
2598                 }
2599
2600                 for (i = 0; i < old_blob.current.count; i++) {
2601                         struct AuthenticationInformation *o =
2602                                 &old_blob.current.array[i];
2603                         struct AuthenticationInformation *p =
2604                                 &new_blob.previous.array[i];
2605
2606                         *p = *o;
2607                         new_blob.previous.count++;
2608                 }
2609                 for (; i < new_blob.count; i++) {
2610                         struct AuthenticationInformation *pi =
2611                                 &new_blob.previous.array[i];
2612
2613                         if (i == 0) {
2614                                 /*
2615                                  * new_blob.previous is still empty so
2616                                  * we'll do new_blob.previous = new_blob.current
2617                                  * below.
2618                                  */
2619                                 break;
2620                         }
2621
2622                         pi->LastUpdateTime = now;
2623                         pi->AuthType = TRUST_AUTH_TYPE_NONE;
2624                         new_blob.previous.count++;
2625                 }
2626
2627                 for (i = 0; i < new_blob.count; i++) {
2628                         struct AuthenticationInformation *ci =
2629                                 &new_blob.current.array[i];
2630
2631                         ci->LastUpdateTime = now;
2632                         switch (i) {
2633                         case 0:
2634                                 if (ntNewHash != NULL) {
2635                                         ci->AuthType = TRUST_AUTH_TYPE_NT4OWF;
2636                                         ci->AuthInfo.nt4owf.password = *ntNewHash;
2637                                         break;
2638                                 }
2639
2640                                 ci->AuthType = TRUST_AUTH_TYPE_CLEAR;
2641                                 ci->AuthInfo.clear.size = new_password->length;
2642                                 ci->AuthInfo.clear.password = new_password->data;
2643                                 break;
2644                         case 1:
2645                                 ci->AuthType = TRUST_AUTH_TYPE_VERSION;
2646                                 ci->AuthInfo.version.version = *new_version;
2647                                 break;
2648                         default:
2649                                 ci->AuthType = TRUST_AUTH_TYPE_NONE;
2650                                 break;
2651                         }
2652
2653                         new_blob.current.count++;
2654                 }
2655
2656                 if (new_blob.previous.count == 0) {
2657                         TALLOC_FREE(new_blob.previous.array);
2658                         new_blob.previous = new_blob.current;
2659                 }
2660
2661                 ndr_err = ndr_push_struct_blob(&new_val, frame, &new_blob,
2662                                 (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
2663                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2664                         ldb_transaction_cancel(ldb);
2665                         DEBUG(1, ("samdb_set_password_sid: "
2666                                   "failed(%s) to generate "
2667                                   "trustAuthOutgoing sAMAccountName[%s] "
2668                                   "DN[%s] TDO[%s], "
2669                                   "returning UNSUCCESSFUL\n",
2670                                   ndr_map_error2string(ndr_err),
2671                                   account_name,
2672                                   ldb_dn_get_linearized(user_msg->dn),
2673                                   ldb_dn_get_linearized(tdo_msg->dn)));
2674                         TALLOC_FREE(frame);
2675                         return NT_STATUS_UNSUCCESSFUL;
2676                 }
2677
2678                 tdo_msg->num_elements = 0;
2679                 TALLOC_FREE(tdo_msg->elements);
2680
2681                 ret = ldb_msg_add_empty(tdo_msg, "trustAuthIncoming",
2682                                         LDB_FLAG_MOD_REPLACE, NULL);
2683                 if (ret != LDB_SUCCESS) {
2684                         ldb_transaction_cancel(ldb);
2685                         TALLOC_FREE(frame);
2686                         return NT_STATUS_NO_MEMORY;
2687                 }
2688                 ret = ldb_msg_add_value(tdo_msg, "trustAuthIncoming",
2689                                         &new_val, NULL);
2690                 if (ret != LDB_SUCCESS) {
2691                         ldb_transaction_cancel(ldb);
2692                         TALLOC_FREE(frame);
2693                         return NT_STATUS_NO_MEMORY;
2694                 }
2695
2696                 ret = ldb_modify(ldb, tdo_msg);
2697                 if (ret != LDB_SUCCESS) {
2698                         nt_status = dsdb_ldb_err_to_ntstatus(ret);
2699                         ldb_transaction_cancel(ldb);
2700                         DEBUG(1, ("samdb_set_password_sid: "
2701                                   "failed to replace "
2702                                   "trustAuthOutgoing sAMAccountName[%s] "
2703                                   "DN[%s] TDO[%s], "
2704                                   "%s - %s\n",
2705                                   account_name,
2706                                   ldb_dn_get_linearized(user_msg->dn),
2707                                   ldb_dn_get_linearized(tdo_msg->dn),
2708                                   nt_errstr(nt_status), ldb_errstring(ldb)));
2709                         TALLOC_FREE(frame);
2710                         return nt_status;
2711                 }
2712         }
2713
2714         nt_status = samdb_set_password_internal(ldb, mem_ctx,
2715                                                 user_msg->dn, NULL,
2716                                                 new_password,
2717                                                 lmNewHash, ntNewHash,
2718                                                 lmOldHash, ntOldHash,
2719                                                 reject_reason, _dominfo,
2720                                                 true); /* permit trusts */
2721         if (!NT_STATUS_IS_OK(nt_status)) {
2722                 ldb_transaction_cancel(ldb);
2723                 TALLOC_FREE(frame);
2724                 return nt_status;
2725         }
2726
2727         ret = ldb_transaction_commit(ldb);
2728         if (ret != LDB_SUCCESS) {
2729                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2730                          ldb_dn_get_linearized(user_msg->dn),
2731                          ldb_errstring(ldb)));
2732                 TALLOC_FREE(frame);
2733                 return NT_STATUS_TRANSACTION_ABORTED;
2734         }
2735
2736         TALLOC_FREE(frame);
2737         return NT_STATUS_OK;
2738 }
2739
2740
2741 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
2742                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
2743 {
2744         struct ldb_message *msg;
2745         struct ldb_dn *basedn;
2746         char *sidstr;
2747         int ret;
2748
2749         sidstr = dom_sid_string(mem_ctx, sid);
2750         NT_STATUS_HAVE_NO_MEMORY(sidstr);
2751
2752         /* We might have to create a ForeignSecurityPrincipal, even if this user
2753          * is in our own domain */
2754
2755         msg = ldb_msg_new(sidstr);
2756         if (msg == NULL) {
2757                 talloc_free(sidstr);
2758                 return NT_STATUS_NO_MEMORY;
2759         }
2760
2761         ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2762                                 ldb_get_default_basedn(sam_ctx),
2763                                 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2764                                 &basedn);
2765         if (ret != LDB_SUCCESS) {
2766                 DEBUG(0, ("Failed to find DN for "
2767                           "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2768                 talloc_free(sidstr);
2769                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2770         }
2771
2772         /* add core elements to the ldb_message for the alias */
2773         msg->dn = basedn;
2774         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2775                 talloc_free(sidstr);
2776                 return NT_STATUS_NO_MEMORY;
2777         }
2778
2779         ret = ldb_msg_add_string(msg, "objectClass",
2780                                  "foreignSecurityPrincipal");
2781         if (ret != LDB_SUCCESS) {
2782                 talloc_free(sidstr);
2783                 return NT_STATUS_NO_MEMORY;
2784         }
2785
2786         /* create the alias */
2787         ret = ldb_add(sam_ctx, msg);
2788         if (ret != LDB_SUCCESS) {
2789                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2790                          "record %s: %s\n", 
2791                          ldb_dn_get_linearized(msg->dn),
2792                          ldb_errstring(sam_ctx)));
2793                 talloc_free(sidstr);
2794                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2795         }
2796
2797         *ret_dn = talloc_steal(mem_ctx, msg->dn);
2798         talloc_free(sidstr);
2799
2800         return NT_STATUS_OK;
2801 }
2802
2803
2804 /*
2805   Find the DN of a domain, assuming it to be a dotted.dns name
2806 */
2807
2808 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) 
2809 {
2810         unsigned int i;
2811         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2812         const char *binary_encoded;
2813         const char * const *split_realm;
2814         struct ldb_dn *dn;
2815
2816         if (!tmp_ctx) {
2817                 return NULL;
2818         }
2819
2820         split_realm = (const char * const *)str_list_make(tmp_ctx, dns_domain, ".");
2821         if (!split_realm) {
2822                 talloc_free(tmp_ctx);
2823                 return NULL;
2824         }
2825         dn = ldb_dn_new(mem_ctx, ldb, NULL);
2826         for (i=0; split_realm[i]; i++) {
2827                 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2828                 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2829                         DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2830                                   binary_encoded, ldb_dn_get_linearized(dn)));
2831                         talloc_free(tmp_ctx);
2832                         return NULL;
2833                 }
2834         }
2835         if (!ldb_dn_validate(dn)) {
2836                 DEBUG(2, ("Failed to validated DN %s\n",
2837                           ldb_dn_get_linearized(dn)));
2838                 talloc_free(tmp_ctx);
2839                 return NULL;
2840         }
2841         talloc_free(tmp_ctx);
2842         return dn;
2843 }
2844
2845
2846 /*
2847   Find the DNS equivalent of a DN, in dotted DNS form
2848 */
2849 char *samdb_dn_to_dns_domain(TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
2850 {
2851         int i, num_components = ldb_dn_get_comp_num(dn);
2852         char *dns_name = talloc_strdup(mem_ctx, "");
2853         if (dns_name == NULL) {
2854                 return NULL;
2855         }
2856
2857         for (i=0; i<num_components; i++) {
2858                 const struct ldb_val *v = ldb_dn_get_component_val(dn, i);
2859                 char *s;
2860                 if (v == NULL) {
2861                         talloc_free(dns_name);
2862                         return NULL;
2863                 }
2864                 s = talloc_asprintf_append_buffer(dns_name, "%*.*s.",
2865                                                   (int)v->length, (int)v->length, (char *)v->data);
2866                 if (s == NULL) {
2867                         talloc_free(dns_name);
2868                         return NULL;
2869                 }
2870                 dns_name = s;
2871         }
2872
2873         /* remove the last '.' */
2874         if (dns_name[0] != 0) {
2875                 dns_name[strlen(dns_name)-1] = 0;
2876         }
2877
2878         return dns_name;
2879 }
2880
2881 /*
2882   Find the DNS _msdcs name for a given NTDS GUID. The resulting DNS
2883   name is based on the forest DNS name
2884 */
2885 char *samdb_ntds_msdcs_dns_name(struct ldb_context *samdb,
2886                                 TALLOC_CTX *mem_ctx,
2887                                 const struct GUID *ntds_guid)
2888 {
2889         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2890         const char *guid_str;
2891         struct ldb_dn *forest_dn;
2892         const char *dnsforest;
2893         char *ret;
2894
2895         guid_str = GUID_string(tmp_ctx, ntds_guid);
2896         if (guid_str == NULL) {
2897                 talloc_free(tmp_ctx);
2898                 return NULL;
2899         }
2900         forest_dn = ldb_get_root_basedn(samdb);
2901         if (forest_dn == NULL) {
2902                 talloc_free(tmp_ctx);
2903                 return NULL;
2904         }
2905         dnsforest = samdb_dn_to_dns_domain(tmp_ctx, forest_dn);
2906         if (dnsforest == NULL) {
2907                 talloc_free(tmp_ctx);
2908                 return NULL;
2909         }
2910         ret = talloc_asprintf(mem_ctx, "%s._msdcs.%s", guid_str, dnsforest);
2911         talloc_free(tmp_ctx);
2912         return ret;
2913 }
2914
2915
2916 /*
2917   Find the DN of a domain, be it the netbios or DNS name 
2918 */
2919 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
2920                                   const char *domain_name) 
2921 {
2922         const char * const domain_ref_attrs[] = {
2923                 "ncName", NULL
2924         };
2925         const char * const domain_ref2_attrs[] = {
2926                 NULL
2927         };
2928         struct ldb_result *res_domain_ref;
2929         char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2930         /* find the domain's DN */
2931         int ret_domain = ldb_search(ldb, mem_ctx,
2932                                             &res_domain_ref, 
2933                                             samdb_partitions_dn(ldb, mem_ctx), 
2934                                             LDB_SCOPE_ONELEVEL, 
2935                                             domain_ref_attrs,
2936                                             "(&(nETBIOSName=%s)(objectclass=crossRef))", 
2937                                             escaped_domain);
2938         if (ret_domain != LDB_SUCCESS) {
2939                 return NULL;
2940         }
2941
2942         if (res_domain_ref->count == 0) {
2943                 ret_domain = ldb_search(ldb, mem_ctx,
2944                                                 &res_domain_ref, 
2945                                                 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2946                                                 LDB_SCOPE_BASE,
2947                                                 domain_ref2_attrs,
2948                                                 "(objectclass=domain)");
2949                 if (ret_domain != LDB_SUCCESS) {
2950                         return NULL;
2951                 }
2952
2953                 if (res_domain_ref->count == 1) {
2954                         return res_domain_ref->msgs[0]->dn;
2955                 }
2956                 return NULL;
2957         }
2958
2959         if (res_domain_ref->count > 1) {
2960                 DEBUG(0,("Found %d records matching domain [%s]\n", 
2961                          ret_domain, domain_name));
2962                 return NULL;
2963         }
2964
2965         return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2966
2967 }
2968
2969
2970 /*
2971   use a GUID to find a DN
2972  */
2973 int dsdb_find_dn_by_guid(struct ldb_context *ldb, 
2974                          TALLOC_CTX *mem_ctx,
2975                          const struct GUID *guid,
2976                          uint32_t dsdb_flags,
2977                          struct ldb_dn **dn)
2978 {
2979         int ret;
2980         struct ldb_result *res;
2981         const char *attrs[] = { NULL };
2982         char *guid_str = GUID_string(mem_ctx, guid);
2983
2984         if (!guid_str) {
2985                 return ldb_operr(ldb);
2986         }
2987
2988         ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2989                           DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2990                           DSDB_SEARCH_SHOW_EXTENDED_DN |
2991                           DSDB_SEARCH_ONE_ONLY | dsdb_flags,
2992                           "objectGUID=%s", guid_str);
2993         talloc_free(guid_str);
2994         if (ret != LDB_SUCCESS) {
2995                 return ret;
2996         }
2997
2998         *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2999         talloc_free(res);
3000
3001         return LDB_SUCCESS;
3002 }
3003
3004 /*
3005   use a DN to find a GUID with a given attribute name
3006  */
3007 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
3008                               struct ldb_dn *dn, const char *attribute,
3009                               struct GUID *guid)
3010 {
3011         int ret;
3012         struct ldb_result *res;
3013         const char *attrs[2];
3014         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3015
3016         attrs[0] = attribute;
3017         attrs[1] = NULL;
3018
3019         ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
3020                              DSDB_SEARCH_SHOW_DELETED |
3021                              DSDB_SEARCH_SHOW_RECYCLED);
3022         if (ret != LDB_SUCCESS) {
3023                 talloc_free(tmp_ctx);
3024                 return ret;
3025         }
3026         if (res->count < 1) {
3027                 talloc_free(tmp_ctx);
3028                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3029         }
3030         *guid = samdb_result_guid(res->msgs[0], attribute);
3031         talloc_free(tmp_ctx);
3032         return LDB_SUCCESS;
3033 }
3034
3035 /*
3036   use a DN to find a GUID
3037  */
3038 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
3039                          struct ldb_dn *dn, struct GUID *guid)
3040 {
3041         return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
3042 }
3043
3044
3045
3046 /*
3047  adds the given GUID to the given ldb_message. This value is added
3048  for the given attr_name (may be either "objectGUID" or "parentGUID").
3049  */
3050 int dsdb_msg_add_guid(struct ldb_message *msg,
3051                 struct GUID *guid,
3052                 const char *attr_name)
3053 {
3054         int ret;
3055         struct ldb_val v;
3056         NTSTATUS status;
3057         TALLOC_CTX *tmp_ctx =  talloc_init("dsdb_msg_add_guid");
3058
3059         status = GU