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