dsdb: add vanish links control
[samba.git] / source4 / dsdb / common / util.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba utility functions
4
5    Copyright (C) Andrew Tridgell 2004
6    Copyright (C) Volker Lendecke 2004
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "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/util_runcmd.h"
49
50 /*
51   search the sam for the specified attributes in a specific domain, filter on
52   objectSid being in domain_sid.
53 */
54 int samdb_search_domain(struct ldb_context *sam_ldb,
55                         TALLOC_CTX *mem_ctx, 
56                         struct ldb_dn *basedn,
57                         struct ldb_message ***res,
58                         const char * const *attrs,
59                         const struct dom_sid *domain_sid,
60                         const char *format, ...)  _PRINTF_ATTRIBUTE(7,8)
61 {
62         va_list ap;
63         int i, count;
64
65         va_start(ap, format);
66         count = gendb_search_v(sam_ldb, mem_ctx, basedn,
67                                res, attrs, format, ap);
68         va_end(ap);
69
70         i=0;
71
72         while (i<count) {
73                 struct dom_sid *entry_sid;
74
75                 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
76
77                 if ((entry_sid == NULL) ||
78                     (!dom_sid_in_domain(domain_sid, entry_sid))) {
79                         /* Delete that entry from the result set */
80                         (*res)[i] = (*res)[count-1];
81                         count -= 1;
82                         talloc_free(entry_sid);
83                         continue;
84                 }
85                 talloc_free(entry_sid);
86                 i += 1;
87         }
88
89         return count;
90 }
91
92 /*
93   search the sam for a single string attribute in exactly 1 record
94 */
95 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
96                                   TALLOC_CTX *mem_ctx,
97                                   struct ldb_dn *basedn,
98                                   const char *attr_name,
99                                   const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
100 {
101         int count;
102         const char *attrs[2] = { NULL, NULL };
103         struct ldb_message **res = NULL;
104
105         attrs[0] = attr_name;
106
107         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
108         if (count > 1) {                
109                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
110                          attr_name, format, count));
111         }
112         if (count != 1) {
113                 talloc_free(res);
114                 return NULL;
115         }
116
117         return ldb_msg_find_attr_as_string(res[0], attr_name, NULL);
118 }
119
120 /*
121   search the sam for a single string attribute in exactly 1 record
122 */
123 const char *samdb_search_string(struct ldb_context *sam_ldb,
124                                 TALLOC_CTX *mem_ctx,
125                                 struct ldb_dn *basedn,
126                                 const char *attr_name,
127                                 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
128 {
129         va_list ap;
130         const char *str;
131
132         va_start(ap, format);
133         str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
134         va_end(ap);
135
136         return str;
137 }
138
139 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
140                                TALLOC_CTX *mem_ctx,
141                                struct ldb_dn *basedn,
142                                const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
143 {
144         va_list ap;
145         struct ldb_dn *ret;
146         struct ldb_message **res = NULL;
147         int count;
148
149         va_start(ap, format);
150         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
151         va_end(ap);
152
153         if (count != 1) return NULL;
154
155         ret = talloc_steal(mem_ctx, res[0]->dn);
156         talloc_free(res);
157
158         return ret;
159 }
160
161 /*
162   search the sam for a dom_sid attribute in exactly 1 record
163 */
164 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
165                                      TALLOC_CTX *mem_ctx,
166                                      struct ldb_dn *basedn,
167                                      const char *attr_name,
168                                      const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
169 {
170         va_list ap;
171         int count;
172         struct ldb_message **res;
173         const char *attrs[2] = { NULL, NULL };
174         struct dom_sid *sid;
175
176         attrs[0] = attr_name;
177
178         va_start(ap, format);
179         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
180         va_end(ap);
181         if (count > 1) {                
182                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
183                          attr_name, format, count));
184         }
185         if (count != 1) {
186                 talloc_free(res);
187                 return NULL;
188         }
189         sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
190         talloc_free(res);
191         return sid;     
192 }
193
194 /*
195   return the count of the number of records in the sam matching the query
196 */
197 int samdb_search_count(struct ldb_context *sam_ldb,
198                        TALLOC_CTX *mem_ctx,
199                        struct ldb_dn *basedn,
200                        const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
201 {
202         va_list ap;
203         const char *attrs[] = { NULL };
204         int ret;
205
206         va_start(ap, format);
207         ret = gendb_search_v(sam_ldb, mem_ctx, basedn, NULL, attrs, format, ap);
208         va_end(ap);
209
210         return ret;
211 }
212
213
214 /*
215   search the sam for a single integer attribute in exactly 1 record
216 */
217 unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
218                          TALLOC_CTX *mem_ctx,
219                          unsigned int default_value,
220                          struct ldb_dn *basedn,
221                          const char *attr_name,
222                          const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
223 {
224         va_list ap;
225         int count;
226         struct ldb_message **res;
227         const char *attrs[2] = { NULL, NULL };
228
229         attrs[0] = attr_name;
230
231         va_start(ap, format);
232         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
233         va_end(ap);
234
235         if (count != 1) {
236                 return default_value;
237         }
238
239         return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value);
240 }
241
242 /*
243   search the sam for a single signed 64 bit integer attribute in exactly 1 record
244 */
245 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
246                            TALLOC_CTX *mem_ctx,
247                            int64_t default_value,
248                            struct ldb_dn *basedn,
249                            const char *attr_name,
250                            const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
251 {
252         va_list ap;
253         int count;
254         struct ldb_message **res;
255         const char *attrs[2] = { NULL, NULL };
256
257         attrs[0] = attr_name;
258
259         va_start(ap, format);
260         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
261         va_end(ap);
262
263         if (count != 1) {
264                 return default_value;
265         }
266
267         return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value);
268 }
269
270 /*
271   search the sam for multipe records each giving a single string attribute
272   return the number of matches, or -1 on error
273 */
274 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
275                                  TALLOC_CTX *mem_ctx,
276                                  struct ldb_dn *basedn,
277                                  const char ***strs,
278                                  const char *attr_name,
279                                  const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
280 {
281         va_list ap;
282         int count, i;
283         const char *attrs[2] = { NULL, NULL };
284         struct ldb_message **res = NULL;
285
286         attrs[0] = attr_name;
287
288         va_start(ap, format);
289         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
290         va_end(ap);
291
292         if (count <= 0) {
293                 return count;
294         }
295
296         /* make sure its single valued */
297         for (i=0;i<count;i++) {
298                 if (res[i]->num_elements != 1) {
299                         DEBUG(1,("samdb: search for %s %s not single valued\n", 
300                                  attr_name, format));
301                         talloc_free(res);
302                         return -1;
303                 }
304         }
305
306         *strs = talloc_array(mem_ctx, const char *, count+1);
307         if (! *strs) {
308                 talloc_free(res);
309                 return -1;
310         }
311
312         for (i=0;i<count;i++) {
313                 (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL);
314         }
315         (*strs)[count] = NULL;
316
317         return count;
318 }
319
320 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
321                                const char *attr, struct ldb_dn *default_value)
322 {
323         struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
324         if (!ret_dn) {
325                 return default_value;
326         }
327         return ret_dn;
328 }
329
330 /*
331   pull a rid from a objectSid in a result set. 
332 */
333 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
334                                    const char *attr, uint32_t default_value)
335 {
336         struct dom_sid *sid;
337         uint32_t rid;
338
339         sid = samdb_result_dom_sid(mem_ctx, msg, attr);
340         if (sid == NULL) {
341                 return default_value;
342         }
343         rid = sid->sub_auths[sid->num_auths-1];
344         talloc_free(sid);
345         return rid;
346 }
347
348 /*
349   pull a dom_sid structure from a objectSid in a result set. 
350 */
351 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
352                                      const char *attr)
353 {
354         bool ok;
355         const struct ldb_val *v;
356         struct dom_sid *sid;
357         v = ldb_msg_find_ldb_val(msg, attr);
358         if (v == NULL) {
359                 return NULL;
360         }
361         sid = talloc(mem_ctx, struct dom_sid);
362         if (sid == NULL) {
363                 return NULL;
364         }
365         ok = sid_parse(v->data, v->length, sid);
366         if (!ok) {
367                 talloc_free(sid);
368                 return NULL;
369         }
370         return sid;
371 }
372
373 /*
374   pull a guid structure from a objectGUID in a result set. 
375 */
376 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
377 {
378         const struct ldb_val *v;
379         struct GUID guid;
380         NTSTATUS status;
381
382         v = ldb_msg_find_ldb_val(msg, attr);
383         if (!v) return GUID_zero();
384
385         status = GUID_from_ndr_blob(v, &guid);
386         if (!NT_STATUS_IS_OK(status)) {
387                 return GUID_zero();
388         }
389
390         return guid;
391 }
392
393 /*
394   pull a sid prefix from a objectSid in a result set. 
395   this is used to find the domain sid for a user
396 */
397 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
398                                         const char *attr)
399 {
400         struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
401         if (!sid || sid->num_auths < 1) return NULL;
402         sid->num_auths--;
403         return sid;
404 }
405
406 /*
407   pull a NTTIME in a result set. 
408 */
409 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
410                            NTTIME default_value)
411 {
412         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
413 }
414
415 /*
416  * Windows stores 0 for lastLogoff.
417  * But when a MS DC return the lastLogoff (as Logoff Time)
418  * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
419  * cause windows 2008 and newer version to fail for SMB requests
420  */
421 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
422 {
423         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
424
425         if (ret == 0)
426                 ret = 0x7FFFFFFFFFFFFFFFULL;
427
428         return ret;
429 }
430
431 /*
432  * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
433  * indicate an account doesn't expire.
434  *
435  * When Windows initially creates an account, it sets
436  * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF).  However,
437  * when changing from an account having a specific expiration date to
438  * that account never expiring, it sets accountExpires = 0.
439  *
440  * Consolidate that logic here to allow clearer logic for account expiry in
441  * the rest of the code.
442  */
443 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
444 {
445         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
446                                                  0);
447
448         if (ret == 0)
449                 ret = 0x7FFFFFFFFFFFFFFFULL;
450
451         return ret;
452 }
453
454 /*
455   construct the allow_password_change field from the PwdLastSet attribute and the 
456   domain password settings
457 */
458 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb, 
459                                           TALLOC_CTX *mem_ctx, 
460                                           struct ldb_dn *domain_dn, 
461                                           struct ldb_message *msg, 
462                                           const char *attr)
463 {
464         uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0);
465         int64_t minPwdAge;
466
467         if (attr_time == 0) {
468                 return 0;
469         }
470
471         minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
472
473         /* yes, this is a -= not a += as minPwdAge is stored as the negative
474            of the number of 100-nano-seconds */
475         attr_time -= minPwdAge;
476
477         return attr_time;
478 }
479
480 /*
481   pull a samr_Password structutre from a result set. 
482 */
483 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
484 {
485         struct samr_Password *hash = NULL;
486         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
487         if (val && (val->length >= sizeof(hash->hash))) {
488                 hash = talloc(mem_ctx, struct samr_Password);
489                 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
490         }
491         return hash;
492 }
493
494 /*
495   pull an array of samr_Password structures from a result set.
496 */
497 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
498                            const char *attr, struct samr_Password **hashes)
499 {
500         unsigned int count, i;
501         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
502
503         *hashes = NULL;
504         if (!val) {
505                 return 0;
506         }
507         count = val->length / 16;
508         if (count == 0) {
509                 return 0;
510         }
511
512         *hashes = talloc_array(mem_ctx, struct samr_Password, count);
513         if (! *hashes) {
514                 return 0;
515         }
516
517         for (i=0;i<count;i++) {
518                 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
519         }
520
521         return count;
522 }
523
524 NTSTATUS samdb_result_passwords_from_history(TALLOC_CTX *mem_ctx,
525                                              struct loadparm_context *lp_ctx,
526                                              struct ldb_message *msg,
527                                              unsigned int idx,
528                                              struct samr_Password **lm_pwd,
529                                              struct samr_Password **nt_pwd)
530 {
531         struct samr_Password *lmPwdHash, *ntPwdHash;
532
533         if (nt_pwd) {
534                 unsigned int num_nt;
535                 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHistory", &ntPwdHash);
536                 if (num_nt <= idx) {
537                         *nt_pwd = NULL;
538                 } else {
539                         *nt_pwd = &ntPwdHash[idx];
540                 }
541         }
542         if (lm_pwd) {
543                 /* Ensure that if we have turned off LM
544                  * authentication, that we never use the LM hash, even
545                  * if we store it */
546                 if (lpcfg_lanman_auth(lp_ctx)) {
547                         unsigned int num_lm;
548                         num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHistory", &lmPwdHash);
549                         if (num_lm <= idx) {
550                                 *lm_pwd = NULL;
551                         } else {
552                                 *lm_pwd = &lmPwdHash[idx];
553                         }
554                 } else {
555                         *lm_pwd = NULL;
556                 }
557         }
558         return NT_STATUS_OK;
559 }
560
561 NTSTATUS samdb_result_passwords_no_lockout(TALLOC_CTX *mem_ctx,
562                                            struct loadparm_context *lp_ctx,
563                                            const struct ldb_message *msg,
564                                            struct samr_Password **lm_pwd,
565                                            struct samr_Password **nt_pwd)
566 {
567         struct samr_Password *lmPwdHash, *ntPwdHash;
568
569         if (nt_pwd) {
570                 unsigned int num_nt;
571                 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
572                 if (num_nt == 0) {
573                         *nt_pwd = NULL;
574                 } else if (num_nt > 1) {
575                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
576                 } else {
577                         *nt_pwd = &ntPwdHash[0];
578                 }
579         }
580         if (lm_pwd) {
581                 /* Ensure that if we have turned off LM
582                  * authentication, that we never use the LM hash, even
583                  * if we store it */
584                 if (lpcfg_lanman_auth(lp_ctx)) {
585                         unsigned int num_lm;
586                         num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
587                         if (num_lm == 0) {
588                                 *lm_pwd = NULL;
589                         } else if (num_lm > 1) {
590                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
591                         } else {
592                                 *lm_pwd = &lmPwdHash[0];
593                         }
594                 } else {
595                         *lm_pwd = NULL;
596                 }
597         }
598         return NT_STATUS_OK;
599 }
600
601 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx,
602                                 struct loadparm_context *lp_ctx,
603                                 const struct ldb_message *msg,
604                                 struct samr_Password **lm_pwd,
605                                 struct samr_Password **nt_pwd)
606 {
607         uint16_t acct_flags;
608
609         acct_flags = samdb_result_acct_flags(msg,
610                                              "msDS-User-Account-Control-Computed");
611         /* Quit if the account was locked out. */
612         if (acct_flags & ACB_AUTOLOCK) {
613                 DEBUG(3,("samdb_result_passwords: Account for user %s was locked out.\n",
614                          ldb_dn_get_linearized(msg->dn)));
615                 return NT_STATUS_ACCOUNT_LOCKED_OUT;
616         }
617
618         return samdb_result_passwords_no_lockout(mem_ctx, lp_ctx, msg,
619                                                  lm_pwd, nt_pwd);
620 }
621
622 /*
623   pull a samr_LogonHours structutre from a result set. 
624 */
625 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
626 {
627         struct samr_LogonHours hours;
628         size_t units_per_week = 168;
629         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
630
631         ZERO_STRUCT(hours);
632
633         if (val) {
634                 units_per_week = val->length * 8;
635         }
636
637         hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
638         if (!hours.bits) {
639                 return hours;
640         }
641         hours.units_per_week = units_per_week;
642         memset(hours.bits, 0xFF, units_per_week/8);
643         if (val) {
644                 memcpy(hours.bits, val->data, val->length);
645         }
646
647         return hours;
648 }
649
650 /*
651   pull a set of account_flags from a result set. 
652
653   Naturally, this requires that userAccountControl and
654   (if not null) the attributes 'attr' be already
655   included in msg
656 */
657 uint32_t samdb_result_acct_flags(const struct ldb_message *msg, const char *attr)
658 {
659         uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
660         uint32_t attr_flags = 0;
661         uint32_t acct_flags = ds_uf2acb(userAccountControl);
662         if (attr) {
663                 attr_flags = ldb_msg_find_attr_as_uint(msg, attr, UF_ACCOUNTDISABLE);
664                 if (attr_flags == UF_ACCOUNTDISABLE) {
665                         DEBUG(0, ("Attribute %s not found, disabling account %s!\n", attr,
666                                   ldb_dn_get_linearized(msg->dn)));
667                 }
668                 acct_flags |= ds_uf2acb(attr_flags);
669         }
670
671         return acct_flags;
672 }
673
674 NTSTATUS samdb_result_parameters(TALLOC_CTX *mem_ctx,
675                                  struct ldb_message *msg,
676                                  const char *attr,
677                                  struct lsa_BinaryString *s)
678 {
679         int i;
680         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
681
682         ZERO_STRUCTP(s);
683
684         if (!val) {
685                 return NT_STATUS_OK;
686         }
687
688         if ((val->length % 2) != 0) {
689                 /*
690                  * If the on-disk data is not even in length, we know
691                  * it is corrupt, and can not be safely pushed.  We
692                  * would either truncate, send either a un-initilaised
693                  * byte or send a forced zero byte
694                  */
695                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
696         }
697
698         s->array = talloc_array(mem_ctx, uint16_t, val->length/2);
699         if (!s->array) {
700                 return NT_STATUS_NO_MEMORY;
701         }
702         s->length = s->size = val->length;
703
704         /* The on-disk format is the 'network' format, being UTF16LE (sort of) */
705         for (i = 0; i < s->length / 2; i++) {
706                 s->array[i] = SVAL(val->data, i * 2);
707         }
708
709         return NT_STATUS_OK;
710 }
711
712 /* Find an attribute, with a particular value */
713
714 /* The current callers of this function expect a very specific
715  * behaviour: In particular, objectClass subclass equivilance is not
716  * wanted.  This means that we should not lookup the schema for the
717  * comparison function */
718 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb, 
719                                                  const struct ldb_message *msg, 
720                                                  const char *name, const char *value)
721 {
722         unsigned int i;
723         struct ldb_message_element *el = ldb_msg_find_element(msg, name);
724
725         if (!el) {
726                 return NULL;
727         }
728
729         for (i=0;i<el->num_values;i++) {
730                 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
731                         return el;
732                 }
733         }
734
735         return NULL;
736 }
737
738 static int samdb_find_or_add_attribute_ex(struct ldb_context *ldb,
739                                           struct ldb_message *msg,
740                                           const char *name,
741                                           const char *set_value,
742                                           unsigned attr_flags,
743                                           bool *added)
744 {
745         int ret;
746         struct ldb_message_element *el;
747
748         SMB_ASSERT(attr_flags != 0);
749
750         el = ldb_msg_find_element(msg, name);
751         if (el) {
752                 if (added != NULL) {
753                         *added = false;
754                 }
755
756                 return LDB_SUCCESS;
757         }
758
759         ret = ldb_msg_add_empty(msg, name,
760                                 attr_flags,
761                                 &el);
762         if (ret != LDB_SUCCESS) {
763                 return ret;
764         }
765
766         if (set_value != NULL) {
767                 ret = ldb_msg_add_string(msg, name, set_value);
768                 if (ret != LDB_SUCCESS) {
769                         return ret;
770                 }
771         }
772
773         if (added != NULL) {
774                 *added = true;
775         }
776         return LDB_SUCCESS;
777 }
778
779 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
780 {
781         return samdb_find_or_add_attribute_ex(ldb, msg, name, set_value, LDB_FLAG_MOD_ADD, NULL);
782 }
783
784 /*
785   add a dom_sid element to a message
786 */
787 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
788                           const char *attr_name, const struct dom_sid *sid)
789 {
790         struct ldb_val v;
791         enum ndr_err_code ndr_err;
792
793         ndr_err = ndr_push_struct_blob(&v, mem_ctx, 
794                                        sid,
795                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
796         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
797                 return ldb_operr(sam_ldb);
798         }
799         return ldb_msg_add_value(msg, attr_name, &v, NULL);
800 }
801
802
803 /*
804   add a delete element operation to a message
805 */
806 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
807                          const char *attr_name)
808 {
809         /* we use an empty replace rather than a delete, as it allows for 
810            dsdb_replace() to be used everywhere */
811         return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
812 }
813
814 /*
815   add an add attribute value to a message or enhance an existing attribute
816   which has the same name and the add flag set.
817 */
818 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
819                          struct ldb_message *msg, const char *attr_name,
820                          const char *value)
821 {
822         struct ldb_message_element *el;
823         struct ldb_val val, *vals;
824         char *v;
825         unsigned int i;
826         bool found = false;
827         int ret;
828
829         v = talloc_strdup(mem_ctx, value);
830         if (v == NULL) {
831                 return ldb_oom(sam_ldb);
832         }
833
834         val.data = (uint8_t *) v;
835         val.length = strlen(v);
836
837         if (val.length == 0) {
838                 /* allow empty strings as non-existent attributes */
839                 return LDB_SUCCESS;
840         }
841
842         for (i = 0; i < msg->num_elements; i++) {
843                 el = &msg->elements[i];
844                 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
845                     (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
846                         found = true;
847                         break;
848                 }
849         }
850         if (!found) {
851                 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
852                                         &el);
853                 if (ret != LDB_SUCCESS) {
854                         return ret;
855                 }
856         }
857
858         vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
859                               el->num_values + 1);
860         if (vals == NULL) {
861                 return ldb_oom(sam_ldb);
862         }
863         el->values = vals;
864         el->values[el->num_values] = val;
865         ++(el->num_values);
866
867         return LDB_SUCCESS;
868 }
869
870 /*
871   add a delete attribute value to a message or enhance an existing attribute
872   which has the same name and the delete flag set.
873 */
874 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
875                          struct ldb_message *msg, const char *attr_name,
876                          const char *value)
877 {
878         struct ldb_message_element *el;
879         struct ldb_val val, *vals;
880         char *v;
881         unsigned int i;
882         bool found = false;
883         int ret;
884
885         v = talloc_strdup(mem_ctx, value);
886         if (v == NULL) {
887                 return ldb_oom(sam_ldb);
888         }
889
890         val.data = (uint8_t *) v;
891         val.length = strlen(v);
892
893         if (val.length == 0) {
894                 /* allow empty strings as non-existent attributes */
895                 return LDB_SUCCESS;
896         }
897
898         for (i = 0; i < msg->num_elements; i++) {
899                 el = &msg->elements[i];
900                 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
901                     (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
902                         found = true;
903                         break;
904                 }
905         }
906         if (!found) {
907                 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
908                                         &el);
909                 if (ret != LDB_SUCCESS) {
910                         return ret;
911                 }
912         }
913
914         vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
915                               el->num_values + 1);
916         if (vals == NULL) {
917                 return ldb_oom(sam_ldb);
918         }
919         el->values = vals;
920         el->values[el->num_values] = val;
921         ++(el->num_values);
922
923         return LDB_SUCCESS;
924 }
925
926 /*
927   add a int element to a message
928 */
929 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
930                        const char *attr_name, int v)
931 {
932         const char *s = talloc_asprintf(mem_ctx, "%d", v);
933         if (s == NULL) {
934                 return ldb_oom(sam_ldb);
935         }
936         return ldb_msg_add_string(msg, attr_name, s);
937 }
938
939 /*
940  * Add an unsigned int element to a message
941  *
942  * The issue here is that we have not yet first cast to int32_t explicitly,
943  * before we cast to an signed int to printf() into the %d or cast to a
944  * int64_t before we then cast to a long long to printf into a %lld.
945  *
946  * There are *no* unsigned integers in Active Directory LDAP, even the RID
947  * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
948  * (See the schema, and the syntax definitions in schema_syntax.c).
949  *
950  */
951 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
952                        const char *attr_name, unsigned int v)
953 {
954         return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
955 }
956
957 /*
958   add a (signed) int64_t element to a message
959 */
960 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
961                         const char *attr_name, int64_t v)
962 {
963         const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
964         if (s == NULL) {
965                 return ldb_oom(sam_ldb);
966         }
967         return ldb_msg_add_string(msg, attr_name, s);
968 }
969
970 /*
971  * Add an unsigned int64_t (uint64_t) element to a message
972  *
973  * The issue here is that we have not yet first cast to int32_t explicitly,
974  * before we cast to an signed int to printf() into the %d or cast to a
975  * int64_t before we then cast to a long long to printf into a %lld.
976  *
977  * There are *no* unsigned integers in Active Directory LDAP, even the RID
978  * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
979  * (See the schema, and the syntax definitions in schema_syntax.c).
980  *
981  */
982 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
983                         const char *attr_name, uint64_t v)
984 {
985         return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
986 }
987
988 /*
989   add a samr_Password element to a message
990 */
991 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
992                        const char *attr_name, const struct samr_Password *hash)
993 {
994         struct ldb_val val;
995         val.data = talloc_memdup(mem_ctx, hash->hash, 16);
996         if (!val.data) {
997                 return ldb_oom(sam_ldb);
998         }
999         val.length = 16;
1000         return ldb_msg_add_value(msg, attr_name, &val, NULL);
1001 }
1002
1003 /*
1004   add a samr_Password array to a message
1005 */
1006 int samdb_msg_add_hashes(struct ldb_context *ldb,
1007                          TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1008                          const char *attr_name, struct samr_Password *hashes,
1009                          unsigned int count)
1010 {
1011         struct ldb_val val;
1012         unsigned int i;
1013         val.data = talloc_array_size(mem_ctx, 16, count);
1014         val.length = count*16;
1015         if (!val.data) {
1016                 return ldb_oom(ldb);
1017         }
1018         for (i=0;i<count;i++) {
1019                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
1020         }
1021         return ldb_msg_add_value(msg, attr_name, &val, NULL);
1022 }
1023
1024 /*
1025   add a acct_flags element to a message
1026 */
1027 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1028                              const char *attr_name, uint32_t v)
1029 {
1030         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1031 }
1032
1033 /*
1034   add a logon_hours element to a message
1035 */
1036 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1037                               const char *attr_name, struct samr_LogonHours *hours)
1038 {
1039         struct ldb_val val;
1040         val.length = hours->units_per_week / 8;
1041         val.data = hours->bits;
1042         return ldb_msg_add_value(msg, attr_name, &val, NULL);
1043 }
1044
1045 /*
1046   add a parameters element to a message
1047 */
1048 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1049                              const char *attr_name, struct lsa_BinaryString *parameters)
1050 {
1051         int i;
1052         struct ldb_val val;
1053         if ((parameters->length % 2) != 0) {
1054                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1055         }
1056
1057         val.data = talloc_array(mem_ctx, uint8_t, parameters->length);
1058         if (val.data == NULL) {
1059                 return LDB_ERR_OPERATIONS_ERROR;
1060         }
1061         val.length = parameters->length;
1062         for (i = 0; i < parameters->length / 2; i++) {
1063                 /*
1064                  * The on-disk format needs to be in the 'network'
1065                  * format, parmeters->array is a uint16_t array of
1066                  * length parameters->length / 2
1067                  */
1068                 SSVAL(val.data, i * 2, parameters->array[i]);
1069         }
1070         return ldb_msg_add_steal_value(msg, attr_name, &val);
1071 }
1072
1073 /*
1074  * Sets an unsigned int element in a message
1075  *
1076  * The issue here is that we have not yet first cast to int32_t explicitly,
1077  * before we cast to an signed int to printf() into the %d or cast to a
1078  * int64_t before we then cast to a long long to printf into a %lld.
1079  *
1080  * There are *no* unsigned integers in Active Directory LDAP, even the RID
1081  * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
1082  * (See the schema, and the syntax definitions in schema_syntax.c).
1083  *
1084  */
1085 int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1086                        struct ldb_message *msg, const char *attr_name,
1087                        unsigned int v)
1088 {
1089         struct ldb_message_element *el;
1090
1091         el = ldb_msg_find_element(msg, attr_name);
1092         if (el) {
1093                 el->num_values = 0;
1094         }
1095         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
1096 }
1097
1098 /*
1099  * Handle ldb_request in transaction
1100  */
1101 int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1102                                  struct ldb_request *req)
1103 {
1104         int ret;
1105
1106         ret = ldb_transaction_start(sam_ldb);
1107         if (ret != LDB_SUCCESS) {
1108                 return ret;
1109         }
1110
1111         ret = ldb_request(sam_ldb, req);
1112         if (ret == LDB_SUCCESS) {
1113                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1114         }
1115
1116         if (ret == LDB_SUCCESS) {
1117                 return ldb_transaction_commit(sam_ldb);
1118         }
1119         ldb_transaction_cancel(sam_ldb);
1120
1121         return ret;
1122 }
1123
1124 /*
1125   return a default security descriptor
1126 */
1127 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1128 {
1129         struct security_descriptor *sd;
1130
1131         sd = security_descriptor_initialise(mem_ctx);
1132
1133         return sd;
1134 }
1135
1136 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) 
1137 {
1138         struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1139         struct ldb_dn *aggregate_dn;
1140         if (!schema_dn) {
1141                 return NULL;
1142         }
1143
1144         aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1145         if (!aggregate_dn) {
1146                 return NULL;
1147         }
1148         if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1149                 return NULL;
1150         }
1151         return aggregate_dn;
1152 }
1153
1154 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1155 {
1156         struct ldb_dn *new_dn;
1157
1158         new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1159         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1160                 talloc_free(new_dn);
1161                 return NULL;
1162         }
1163         return new_dn;
1164 }
1165
1166 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1167 {
1168        struct ldb_dn *new_dn;
1169
1170        new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1171        if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1172                talloc_free(new_dn);
1173                return NULL;
1174        }
1175        return new_dn;
1176 }
1177
1178 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1179 {
1180         struct ldb_dn *new_dn;
1181
1182         new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1183         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1184                 talloc_free(new_dn);
1185                 return NULL;
1186         }
1187         return new_dn;
1188 }
1189
1190 /*
1191   work out the domain sid for the current open ldb
1192 */
1193 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1194 {
1195         TALLOC_CTX *tmp_ctx;
1196         const struct dom_sid *domain_sid;
1197         const char *attrs[] = {
1198                 "objectSid",
1199                 NULL
1200         };
1201         struct ldb_result *res;
1202         int ret;
1203
1204         /* see if we have a cached copy */
1205         domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1206         if (domain_sid) {
1207                 return domain_sid;
1208         }
1209
1210         tmp_ctx = talloc_new(ldb);
1211         if (tmp_ctx == NULL) {
1212                 goto failed;
1213         }
1214
1215         ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1216
1217         if (ret != LDB_SUCCESS) {
1218                 goto failed;
1219         }
1220
1221         if (res->count != 1) {
1222                 goto failed;
1223         }
1224
1225         domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1226         if (domain_sid == NULL) {
1227                 goto failed;
1228         }
1229
1230         /* cache the domain_sid in the ldb */
1231         if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1232                 goto failed;
1233         }
1234
1235         talloc_steal(ldb, domain_sid);
1236         talloc_free(tmp_ctx);
1237
1238         return domain_sid;
1239
1240 failed:
1241         talloc_free(tmp_ctx);
1242         return NULL;
1243 }
1244
1245 /*
1246   get domain sid from cache
1247 */
1248 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1249 {
1250         return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1251 }
1252
1253 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1254 {
1255         TALLOC_CTX *tmp_ctx;
1256         struct dom_sid *dom_sid_new;
1257         struct dom_sid *dom_sid_old;
1258
1259         /* see if we have a cached copy */
1260         dom_sid_old = talloc_get_type(ldb_get_opaque(ldb, 
1261                                                      "cache.domain_sid"), struct dom_sid);
1262
1263         tmp_ctx = talloc_new(ldb);
1264         if (tmp_ctx == NULL) {
1265                 goto failed;
1266         }
1267
1268         dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1269         if (!dom_sid_new) {
1270                 goto failed;
1271         }
1272
1273         /* cache the domain_sid in the ldb */
1274         if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1275                 goto failed;
1276         }
1277
1278         talloc_steal(ldb, dom_sid_new);
1279         talloc_free(tmp_ctx);
1280         talloc_free(dom_sid_old);
1281
1282         return true;
1283
1284 failed:
1285         DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1286         talloc_free(tmp_ctx);
1287         return false;
1288 }
1289
1290 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1291 {
1292         TALLOC_CTX *tmp_ctx;
1293         struct ldb_dn *ntds_settings_dn_new;
1294         struct ldb_dn *ntds_settings_dn_old;
1295
1296         /* see if we have a forced copy from provision */
1297         ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb, 
1298                                                               "forced.ntds_settings_dn"), struct ldb_dn);
1299
1300         tmp_ctx = talloc_new(ldb);
1301         if (tmp_ctx == NULL) {
1302                 goto failed;
1303         }
1304
1305         ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1306         if (!ntds_settings_dn_new) {
1307                 goto failed;
1308         }
1309
1310         /* set the DN in the ldb to avoid lookups during provision */
1311         if (ldb_set_opaque(ldb, "forced.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1312                 goto failed;
1313         }
1314
1315         talloc_steal(ldb, ntds_settings_dn_new);
1316         talloc_free(tmp_ctx);
1317         talloc_free(ntds_settings_dn_old);
1318
1319         return true;
1320
1321 failed:
1322         DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1323         talloc_free(tmp_ctx);
1324         return false;
1325 }
1326
1327 /*
1328   work out the ntds settings dn for the current open ldb
1329 */
1330 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1331 {
1332         TALLOC_CTX *tmp_ctx;
1333         const char *root_attrs[] = { "dsServiceName", NULL };
1334         int ret;
1335         struct ldb_result *root_res;
1336         struct ldb_dn *settings_dn;
1337
1338         /* see if we have a cached copy */
1339         settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "forced.ntds_settings_dn");
1340         if (settings_dn) {
1341                 return ldb_dn_copy(mem_ctx, settings_dn);
1342         }
1343
1344         tmp_ctx = talloc_new(mem_ctx);
1345         if (tmp_ctx == NULL) {
1346                 goto failed;
1347         }
1348
1349         ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1350         if (ret != LDB_SUCCESS) {
1351                 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n", 
1352                          ldb_errstring(ldb)));
1353                 goto failed;
1354         }
1355
1356         if (root_res->count != 1) {
1357                 goto failed;
1358         }
1359
1360         settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1361
1362         /* note that we do not cache the DN here, as that would mean
1363          * we could not handle server renames at runtime. Only
1364          * provision sets up forced.ntds_settings_dn */
1365
1366         talloc_steal(mem_ctx, settings_dn);
1367         talloc_free(tmp_ctx);
1368
1369         return settings_dn;
1370
1371 failed:
1372         DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1373         talloc_free(tmp_ctx);
1374         return NULL;
1375 }
1376
1377 /*
1378   work out the ntds settings invocationId for the current open ldb
1379 */
1380 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1381 {
1382         TALLOC_CTX *tmp_ctx;
1383         const char *attrs[] = { "invocationId", NULL };
1384         int ret;
1385         struct ldb_result *res;
1386         struct GUID *invocation_id;
1387
1388         /* see if we have a cached copy */
1389         invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1390         if (invocation_id) {
1391                 SMB_ASSERT(!GUID_all_zero(invocation_id));
1392                 return invocation_id;
1393         }
1394
1395         tmp_ctx = talloc_new(ldb);
1396         if (tmp_ctx == NULL) {
1397                 goto failed;
1398         }
1399
1400         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
1401         if (ret) {
1402                 goto failed;
1403         }
1404
1405         if (res->count != 1) {
1406                 goto failed;
1407         }
1408
1409         invocation_id = talloc(tmp_ctx, struct GUID);
1410         if (!invocation_id) {
1411                 goto failed;
1412         }
1413
1414         *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1415         if (GUID_all_zero(invocation_id)) {
1416                 if (ldb_msg_find_ldb_val(res->msgs[0], "invocationId")) {
1417                         DEBUG(0, ("Failed to find our own NTDS Settings invocationId in the ldb!\n"));  
1418                 } else {
1419                         DEBUG(0, ("Failed to find parse own NTDS Settings invocationId from the ldb!\n"));
1420                 }
1421                 goto failed;
1422         }
1423
1424         /* cache the domain_sid in the ldb */
1425         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1426                 goto failed;
1427         }
1428
1429         talloc_steal(ldb, invocation_id);
1430         talloc_free(tmp_ctx);
1431
1432         return invocation_id;
1433
1434 failed:
1435         DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1436         talloc_free(tmp_ctx);
1437         return NULL;
1438 }
1439
1440 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1441 {
1442         TALLOC_CTX *tmp_ctx;
1443         struct GUID *invocation_id_new;
1444         struct GUID *invocation_id_old;
1445
1446         /* see if we have a cached copy */
1447         invocation_id_old = (struct GUID *)ldb_get_opaque(ldb, 
1448                                                          "cache.invocation_id");
1449
1450         tmp_ctx = talloc_new(ldb);
1451         if (tmp_ctx == NULL) {
1452                 goto failed;
1453         }
1454
1455         invocation_id_new = talloc(tmp_ctx, struct GUID);
1456         if (!invocation_id_new) {
1457                 goto failed;
1458         }
1459
1460         SMB_ASSERT(!GUID_all_zero(invocation_id_in));
1461         *invocation_id_new = *invocation_id_in;
1462
1463         /* cache the domain_sid in the ldb */
1464         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1465                 goto failed;
1466         }
1467
1468         talloc_steal(ldb, invocation_id_new);
1469         talloc_free(tmp_ctx);
1470         talloc_free(invocation_id_old);
1471
1472         return true;
1473
1474 failed:
1475         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1476         talloc_free(tmp_ctx);
1477         return false;
1478 }
1479
1480 /*
1481   work out the ntds settings objectGUID for the current open ldb
1482 */
1483 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1484 {
1485         TALLOC_CTX *tmp_ctx;
1486         const char *attrs[] = { "objectGUID", NULL };
1487         int ret;
1488         struct ldb_result *res;
1489         struct GUID *ntds_guid;
1490
1491         /* see if we have a cached copy */
1492         ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1493         if (ntds_guid) {
1494                 return ntds_guid;
1495         }
1496
1497         tmp_ctx = talloc_new(ldb);
1498         if (tmp_ctx == NULL) {
1499                 goto failed;
1500         }
1501
1502         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
1503         if (ret) {
1504                 goto failed;
1505         }
1506
1507         if (res->count != 1) {
1508                 goto failed;
1509         }
1510
1511         ntds_guid = talloc(tmp_ctx, struct GUID);
1512         if (!ntds_guid) {
1513                 goto failed;
1514         }
1515
1516         *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1517
1518         /* cache the domain_sid in the ldb */
1519         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1520                 goto failed;
1521         }
1522
1523         talloc_steal(ldb, ntds_guid);
1524         talloc_free(tmp_ctx);
1525
1526         return ntds_guid;
1527
1528 failed:
1529         DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1530         talloc_free(tmp_ctx);
1531         return NULL;
1532 }
1533
1534 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1535 {
1536         TALLOC_CTX *tmp_ctx;
1537         struct GUID *ntds_guid_new;
1538         struct GUID *ntds_guid_old;
1539
1540         /* see if we have a cached copy */
1541         ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1542
1543         tmp_ctx = talloc_new(ldb);
1544         if (tmp_ctx == NULL) {
1545                 goto failed;
1546         }
1547
1548         ntds_guid_new = talloc(tmp_ctx, struct GUID);
1549         if (!ntds_guid_new) {
1550                 goto failed;
1551         }
1552
1553         *ntds_guid_new = *ntds_guid_in;
1554
1555         /* cache the domain_sid in the ldb */
1556         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1557                 goto failed;
1558         }
1559
1560         talloc_steal(ldb, ntds_guid_new);
1561         talloc_free(tmp_ctx);
1562         talloc_free(ntds_guid_old);
1563
1564         return true;
1565
1566 failed:
1567         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1568         talloc_free(tmp_ctx);
1569         return false;
1570 }
1571
1572 /*
1573   work out the server dn for the current open ldb
1574 */
1575 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1576 {
1577         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1578         struct ldb_dn *dn;
1579         if (!tmp_ctx) {
1580                 return NULL;
1581         }
1582         dn = ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb, tmp_ctx));
1583         talloc_free(tmp_ctx);
1584         return dn;
1585         
1586 }
1587
1588 /*
1589   work out the server dn for the current open ldb
1590 */
1591 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1592 {
1593         struct ldb_dn *server_dn;
1594         struct ldb_dn *servers_dn;
1595         struct ldb_dn *server_site_dn;
1596
1597         /* TODO: there must be a saner way to do this!! */
1598         server_dn = samdb_server_dn(ldb, mem_ctx);
1599         if (!server_dn) return NULL;
1600
1601         servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1602         talloc_free(server_dn);
1603         if (!servers_dn) return NULL;
1604
1605         server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1606         talloc_free(servers_dn);
1607
1608         return server_site_dn;
1609 }
1610
1611 /*
1612   find the site name from a computers DN record
1613  */
1614 int samdb_find_site_for_computer(struct ldb_context *ldb,
1615                                  TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1616                                  const char **site_name)
1617 {
1618         int ret;
1619         struct ldb_dn *dn;
1620         const struct ldb_val *rdn_val;
1621
1622         *site_name = NULL;
1623
1624         ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1625         if (ret != LDB_SUCCESS) {
1626                 return ret;
1627         }
1628
1629         if (!ldb_dn_remove_child_components(dn, 2)) {
1630                 talloc_free(dn);
1631                 return LDB_ERR_INVALID_DN_SYNTAX;
1632         }
1633
1634         rdn_val = ldb_dn_get_rdn_val(dn);
1635         if (rdn_val == NULL) {
1636                 return LDB_ERR_OPERATIONS_ERROR;
1637         }
1638
1639         (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1640         talloc_free(dn);
1641         if (!*site_name) {
1642                 return LDB_ERR_OPERATIONS_ERROR;
1643         }
1644         return LDB_SUCCESS;
1645 }
1646
1647 /*
1648   find the NTDS GUID from a computers DN record
1649  */
1650 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1651                                      struct GUID *ntds_guid)
1652 {
1653         int ret;
1654         struct ldb_dn *dn;
1655
1656         *ntds_guid = GUID_zero();
1657
1658         ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1659         if (ret != LDB_SUCCESS) {
1660                 return ret;
1661         }
1662
1663         if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1664                 talloc_free(dn);
1665                 return LDB_ERR_OPERATIONS_ERROR;
1666         }
1667
1668         ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1669         talloc_free(dn);
1670         return ret;
1671 }
1672
1673 /*
1674   find a 'reference' DN that points at another object
1675   (eg. serverReference, rIDManagerReference etc)
1676  */
1677 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1678                        const char *attribute, struct ldb_dn **dn)
1679 {
1680         const char *attrs[2];
1681         struct ldb_result *res;
1682         int ret;
1683
1684         attrs[0] = attribute;
1685         attrs[1] = NULL;
1686
1687         ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY|DSDB_SEARCH_SHOW_EXTENDED_DN, NULL);
1688         if (ret != LDB_SUCCESS) {
1689                 ldb_asprintf_errstring(ldb, "Cannot find DN %s to get attribute %s for reference dn: %s",
1690                                        ldb_dn_get_linearized(base), attribute, ldb_errstring(ldb));
1691                 return ret;
1692         }
1693
1694         *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1695         if (!*dn) {
1696                 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1697                         ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1698                                                ldb_dn_get_linearized(base));
1699                 } else {
1700                         ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1701                                                ldb_dn_get_linearized(base));
1702                 }
1703                 talloc_free(res);
1704                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1705         }
1706
1707         talloc_free(res);
1708         return LDB_SUCCESS;
1709 }
1710
1711 /*
1712   find if a DN (must have GUID component!) is our ntdsDsa
1713  */
1714 int samdb_dn_is_our_ntdsa(struct ldb_context *ldb, struct ldb_dn *dn, bool *is_ntdsa)
1715 {
1716         NTSTATUS status;
1717         struct GUID dn_guid;
1718         const struct GUID *our_ntds_guid;
1719         status = dsdb_get_extended_dn_guid(dn, &dn_guid, "GUID");
1720         if (!NT_STATUS_IS_OK(status)) {
1721                 return LDB_ERR_OPERATIONS_ERROR;
1722         }
1723
1724         our_ntds_guid = samdb_ntds_objectGUID(ldb);
1725         if (!our_ntds_guid) {
1726                 DEBUG(0, ("Failed to find our NTDS Settings GUID for comparison with %s - %s\n", ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
1727                 return LDB_ERR_OPERATIONS_ERROR;
1728         }
1729
1730         *is_ntdsa = GUID_equal(&dn_guid, our_ntds_guid);
1731         return LDB_SUCCESS;
1732 }
1733
1734 /*
1735   find a 'reference' DN that points at another object and indicate if it is our ntdsDsa
1736  */
1737 int samdb_reference_dn_is_our_ntdsa(struct ldb_context *ldb, struct ldb_dn *base,
1738                                     const char *attribute, bool *is_ntdsa)
1739 {
1740         int ret;
1741         struct ldb_dn *referenced_dn;
1742         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
1743         if (tmp_ctx == NULL) {
1744                 return LDB_ERR_OPERATIONS_ERROR;
1745         }
1746         ret = samdb_reference_dn(ldb, tmp_ctx, base, attribute, &referenced_dn);
1747         if (ret != LDB_SUCCESS) {
1748                 DEBUG(0, ("Failed to find object %s for attribute %s - %s\n", ldb_dn_get_linearized(base), attribute, ldb_errstring(ldb)));
1749                 return ret;
1750         }
1751
1752         ret = samdb_dn_is_our_ntdsa(ldb, referenced_dn, is_ntdsa);
1753         
1754         talloc_free(tmp_ctx);
1755         return ret;
1756 }
1757
1758 /*
1759   find our machine account via the serverReference attribute in the
1760   server DN
1761  */
1762 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1763 {
1764         struct ldb_dn *server_dn;
1765         int ret;
1766
1767         server_dn = samdb_server_dn(ldb, mem_ctx);
1768         if (server_dn == NULL) {
1769                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
1770         }
1771
1772         ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1773         talloc_free(server_dn);
1774
1775         return ret;
1776 }
1777
1778 /*
1779   find the RID Manager$ DN via the rIDManagerReference attribute in the
1780   base DN
1781  */
1782 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1783 {
1784         return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1785                                   "rIDManagerReference", dn);
1786 }
1787
1788 /*
1789   find the RID Set DN via the rIDSetReferences attribute in our
1790   machine account DN
1791  */
1792 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1793 {
1794         struct ldb_dn *server_ref_dn;
1795         int ret;
1796
1797         ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1798         if (ret != LDB_SUCCESS) {
1799                 return ret;
1800         }
1801         ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1802         talloc_free(server_ref_dn);
1803         return ret;
1804 }
1805
1806 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1807 {
1808         const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1809                                                                             mem_ctx));
1810
1811         if (val == NULL) {
1812                 return NULL;
1813         }
1814
1815         return (const char *) val->data;
1816 }
1817
1818 /*
1819  * Finds the client site by using the client's IP address.
1820  * The "subnet_name" returns the name of the subnet if parameter != NULL
1821  */
1822 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1823                                    const char *ip_address, char **subnet_name)
1824 {
1825         const char *attrs[] = { "cn", "siteObject", NULL };
1826         struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1827         struct ldb_result *res;
1828         const struct ldb_val *val;
1829         const char *site_name = NULL, *l_subnet_name = NULL;
1830         const char *allow_list[2] = { NULL, NULL };
1831         unsigned int i, count;
1832         int cnt, ret;
1833
1834         /*
1835          * if we don't have a client ip e.g. ncalrpc
1836          * the server site is the client site
1837          */
1838         if (ip_address == NULL) {
1839                 return samdb_server_site_name(ldb, mem_ctx);
1840         }
1841
1842         sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1843         if (sites_container_dn == NULL) {
1844                 return NULL;
1845         }
1846
1847         subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1848         if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1849                 talloc_free(sites_container_dn);
1850                 talloc_free(subnets_dn);
1851                 return NULL;
1852         }
1853
1854         ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1855                          attrs, NULL);
1856         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1857                 count = 0;
1858         } else if (ret != LDB_SUCCESS) {
1859                 talloc_free(sites_container_dn);
1860                 talloc_free(subnets_dn);
1861                 return NULL;
1862         } else {
1863                 count = res->count;
1864         }
1865
1866         for (i = 0; i < count; i++) {
1867                 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1868                                                             NULL);
1869
1870                 allow_list[0] = l_subnet_name;
1871
1872                 if (socket_allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1873                         sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1874                                                            res->msgs[i],
1875                                                            "siteObject");
1876                         if (sites_dn == NULL) {
1877                                 /* No reference, maybe another subnet matches */
1878                                 continue;
1879                         }
1880
1881                         /* "val" cannot be NULL here since "sites_dn" != NULL */
1882                         val = ldb_dn_get_rdn_val(sites_dn);
1883                         site_name = talloc_strdup(mem_ctx,
1884                                                   (const char *) val->data);
1885
1886                         talloc_free(sites_dn);
1887
1888                         break;
1889                 }
1890         }
1891
1892         if (site_name == NULL) {
1893                 /* This is the Windows Server fallback rule: when no subnet
1894                  * exists and we have only one site available then use it (it
1895                  * is for sure the same as our server site). If more sites do
1896                  * exist then we don't know which one to use and set the site
1897                  * name to "". */
1898                 cnt = samdb_search_count(ldb, mem_ctx, sites_container_dn,
1899                                          "(objectClass=site)");
1900                 if (cnt == 1) {
1901                         site_name = samdb_server_site_name(ldb, mem_ctx);
1902                 } else {
1903                         site_name = talloc_strdup(mem_ctx, "");
1904                 }
1905                 l_subnet_name = NULL;
1906         }
1907
1908         if (subnet_name != NULL) {
1909                 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1910         }
1911
1912         talloc_free(sites_container_dn);
1913         talloc_free(subnets_dn);
1914         talloc_free(res);
1915
1916         return site_name;
1917 }
1918
1919 /*
1920   work out if we are the PDC for the domain of the current open ldb
1921 */
1922 bool samdb_is_pdc(struct ldb_context *ldb)
1923 {
1924         int ret;
1925         bool is_pdc;
1926
1927         ret = samdb_reference_dn_is_our_ntdsa(ldb, ldb_get_default_basedn(ldb), "fsmoRoleOwner", 
1928                                               &is_pdc);
1929         if (ret != LDB_SUCCESS) {
1930                 DEBUG(1,("Failed to find if we are the PDC for this ldb: Searching for fSMORoleOwner in %s failed: %s\n", 
1931                          ldb_dn_get_linearized(ldb_get_default_basedn(ldb)), 
1932                          ldb_errstring(ldb)));
1933                 return false;
1934         }
1935
1936         return is_pdc;
1937 }
1938
1939 /*
1940   work out if we are a Global Catalog server for the domain of the current open ldb
1941 */
1942 bool samdb_is_gc(struct ldb_context *ldb)
1943 {
1944         uint32_t options;
1945         if (samdb_ntds_options(ldb, &options) != LDB_SUCCESS) {
1946                 return false;
1947         }
1948         return (options & DS_NTDSDSA_OPT_IS_GC) != 0;
1949 }
1950
1951 /* Find a domain object in the parents of a particular DN.  */
1952 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1953                                    struct ldb_dn **parent_dn, const char **errstring)
1954 {
1955         TALLOC_CTX *local_ctx;
1956         struct ldb_dn *sdn = dn;
1957         struct ldb_result *res = NULL;
1958         int ret = LDB_SUCCESS;
1959         const char *attrs[] = { NULL };
1960
1961         local_ctx = talloc_new(mem_ctx);
1962         if (local_ctx == NULL) return ldb_oom(ldb);
1963
1964         while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1965                 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1966                                  "(|(objectClass=domain)(objectClass=builtinDomain))");
1967                 if (ret == LDB_SUCCESS) {
1968                         if (res->count == 1) {
1969                                 break;
1970                         }
1971                 } else {
1972                         break;
1973                 }
1974         }
1975
1976         if (ret != LDB_SUCCESS) {
1977                 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1978                                              ldb_dn_get_linearized(dn),
1979                                              ldb_dn_get_linearized(sdn),
1980                                              ldb_errstring(ldb));
1981                 talloc_free(local_ctx);
1982                 return ret;
1983         }
1984         if (res->count != 1) {
1985                 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1986                                              ldb_dn_get_linearized(dn));
1987                 DEBUG(0,(__location__ ": %s\n", *errstring));
1988                 talloc_free(local_ctx);
1989                 return LDB_ERR_CONSTRAINT_VIOLATION;
1990         }
1991
1992         *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1993         talloc_free(local_ctx);
1994         return ret;
1995 }
1996
1997 static void pwd_timeout_debug(struct tevent_context *unused1,
1998                               struct tevent_timer *unused2,
1999                               struct timeval unused3,
2000                               void *unused4)
2001 {
2002         DEBUG(0, ("WARNING: check_password_complexity: password script "
2003                   "took more than 1 second to run\n"));
2004 }
2005
2006
2007 /*
2008  * Performs checks on a user password (plaintext UNIX format - attribute
2009  * "password"). The remaining parameters have to be extracted from the domain
2010  * object in the AD.
2011  *
2012  * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2013  */
2014 enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx,
2015                                                 struct loadparm_context *lp_ctx,
2016                                                 const DATA_BLOB *utf8_blob,
2017                                                 const uint32_t pwdProperties,
2018                                                 const uint32_t minPwdLength)
2019 {
2020         const char *utf8_pw = (const char *)utf8_blob->data;
2021         size_t utf8_len = strlen_m(utf8_pw);
2022         char *password_script = NULL;
2023
2024         /* checks if the "minPwdLength" property is satisfied */
2025         if (minPwdLength > utf8_len) {
2026                 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2027         }
2028
2029         /* checks the password complexity */
2030         if (!(pwdProperties & DOMAIN_PASSWORD_COMPLEX)) {
2031                 return SAMR_VALIDATION_STATUS_SUCCESS;
2032         }
2033
2034         if (utf8_len == 0) {
2035                 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2036         }
2037
2038         password_script = lpcfg_check_password_script(lp_ctx, mem_ctx);
2039         if (password_script != NULL && *password_script != '\0') {
2040                 int check_ret = 0;
2041                 int error = 0;
2042                 struct tevent_context *event_ctx = NULL;
2043                 struct tevent_req *req = NULL;
2044                 struct samba_runcmd_state *run_cmd = NULL;
2045                 const char * const cmd[4] = {
2046                         "/bin/sh", "-c",
2047                         password_script,
2048                         NULL
2049                 };
2050
2051                 event_ctx = tevent_context_init(mem_ctx);
2052                 if (event_ctx == NULL) {
2053                         TALLOC_FREE(password_script);
2054                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2055                 }
2056
2057                 /* Gives a warning after 1 second, terminates after 10 */
2058                 tevent_add_timer(event_ctx, event_ctx,
2059                                  tevent_timeval_current_ofs(1, 0),
2060                                  pwd_timeout_debug, NULL);
2061
2062                 req = samba_runcmd_send(event_ctx, event_ctx,
2063                                         tevent_timeval_current_ofs(10, 0),
2064                                         100, 100, cmd, NULL);
2065                 run_cmd = tevent_req_data(req, struct samba_runcmd_state);
2066                 if (write(run_cmd->fd_stdin, utf8_pw, utf8_len) != utf8_len) {
2067                         TALLOC_FREE(password_script);
2068                         TALLOC_FREE(event_ctx);
2069                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2070                 }
2071
2072                 close(run_cmd->fd_stdin);
2073                 run_cmd->fd_stdin = -1;
2074
2075                 if (!tevent_req_poll(req, event_ctx)) {
2076                         TALLOC_FREE(password_script);
2077                         TALLOC_FREE(event_ctx);
2078                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2079                 }
2080
2081                 check_ret = samba_runcmd_recv(req, &error);
2082                 TALLOC_FREE(event_ctx);
2083
2084                 if (error == ETIMEDOUT) {
2085                         DEBUG(0, ("check_password_complexity: check password script took too long!\n"));
2086                         TALLOC_FREE(password_script);
2087                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2088                 } else {
2089                         DEBUG(5,("check_password_complexity: check password script (%s) "
2090                                  "returned [%d]\n", password_script, check_ret));
2091
2092                         if (check_ret != 0) {
2093                                 DEBUG(1,("check_password_complexity: "
2094                                          "check password script said new password is not good "
2095                                          "enough!\n"));
2096                                 TALLOC_FREE(password_script);
2097                                 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2098                         }
2099                 }
2100
2101                 TALLOC_FREE(password_script);
2102                 return SAMR_VALIDATION_STATUS_SUCCESS;
2103         }
2104
2105         TALLOC_FREE(password_script);
2106
2107         if (!check_password_quality(utf8_pw)) {
2108                 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2109         }
2110
2111         return SAMR_VALIDATION_STATUS_SUCCESS;
2112 }
2113
2114 /*
2115  * Callback for "samdb_set_password" password change
2116  */
2117 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2118 {
2119         int ret;
2120
2121         if (!ares) {
2122                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2123         }
2124
2125         if (ares->error != LDB_SUCCESS) {
2126                 ret = ares->error;
2127                 req->context = talloc_steal(req,
2128                                             ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2129                 talloc_free(ares);
2130                 return ldb_request_done(req, ret);
2131         }
2132
2133         if (ares->type != LDB_REPLY_DONE) {
2134                 talloc_free(ares);
2135                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2136         }
2137
2138         req->context = talloc_steal(req,
2139                                     ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2140         talloc_free(ares);
2141         return ldb_request_done(req, LDB_SUCCESS);
2142 }
2143
2144 /*
2145  * Sets the user password using plaintext UTF16 (attribute "new_password") or
2146  * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2147  * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2148  * user change or not. The "rejectReason" gives some more information if the
2149  * change failed.
2150  *
2151  * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2152  *   NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2153  */
2154 static NTSTATUS samdb_set_password_internal(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2155                             struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2156                             const DATA_BLOB *new_password,
2157                             const struct samr_Password *lmNewHash,
2158                             const struct samr_Password *ntNewHash,
2159                             const struct samr_Password *lmOldHash,
2160                             const struct samr_Password *ntOldHash,
2161                             enum samPwdChangeReason *reject_reason,
2162                             struct samr_DomInfo1 **_dominfo,
2163                             bool permit_interdomain_trust)
2164 {
2165         struct ldb_message *msg;
2166         struct ldb_message_element *el;
2167         struct ldb_request *req;
2168         struct dsdb_control_password_change_status *pwd_stat = NULL;
2169         int ret;
2170         bool hash_values = false;
2171         NTSTATUS status = NT_STATUS_OK;
2172
2173 #define CHECK_RET(x) \
2174         if (x != LDB_SUCCESS) { \
2175                 talloc_free(msg); \
2176                 return NT_STATUS_NO_MEMORY; \
2177         }
2178
2179         msg = ldb_msg_new(mem_ctx);
2180         if (msg == NULL) {
2181                 return NT_STATUS_NO_MEMORY;
2182         }
2183         msg->dn = user_dn;
2184         if ((new_password != NULL)
2185                         && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2186                 /* we have the password as plaintext UTF16 */
2187                 CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
2188                                             new_password, NULL));
2189                 el = ldb_msg_find_element(msg, "clearTextPassword");
2190                 el->flags = LDB_FLAG_MOD_REPLACE;
2191         } else if ((new_password == NULL)
2192                         && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2193                 /* we have a password as LM and/or NT hash */
2194                 if (lmNewHash != NULL) {
2195                         CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2196                                 "dBCSPwd", lmNewHash));
2197                         el = ldb_msg_find_element(msg, "dBCSPwd");
2198                         el->flags = LDB_FLAG_MOD_REPLACE;
2199                 }
2200                 if (ntNewHash != NULL) {
2201                         CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2202                                 "unicodePwd", ntNewHash));
2203                         el = ldb_msg_find_element(msg, "unicodePwd");
2204                         el->flags = LDB_FLAG_MOD_REPLACE;
2205                 }
2206                 hash_values = true;
2207         } else {
2208                 /* the password wasn't specified correctly */
2209                 talloc_free(msg);
2210                 return NT_STATUS_INVALID_PARAMETER;
2211         }
2212
2213         /* build modify request */
2214         ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2215                                 samdb_set_password_callback, NULL);
2216         if (ret != LDB_SUCCESS) {
2217                 talloc_free(msg);
2218                 return NT_STATUS_NO_MEMORY;
2219         }
2220
2221         /* A password change operation */
2222         if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2223                 struct dsdb_control_password_change *change;
2224
2225                 change = talloc(req, struct dsdb_control_password_change);
2226                 if (change == NULL) {
2227                         talloc_free(req);
2228                         talloc_free(msg);
2229                         return NT_STATUS_NO_MEMORY;
2230                 }
2231
2232                 change->old_nt_pwd_hash = ntOldHash;
2233                 change->old_lm_pwd_hash = lmOldHash;
2234
2235                 ret = ldb_request_add_control(req,
2236                                               DSDB_CONTROL_PASSWORD_CHANGE_OID,
2237                                               true, change);
2238                 if (ret != LDB_SUCCESS) {
2239                         talloc_free(req);
2240                         talloc_free(msg);
2241                         return NT_STATUS_NO_MEMORY;
2242                 }
2243         }
2244         if (hash_values) {
2245                 ret = ldb_request_add_control(req,
2246                                               DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2247                                               true, NULL);
2248                 if (ret != LDB_SUCCESS) {
2249                         talloc_free(req);
2250                         talloc_free(msg);
2251                         return NT_STATUS_NO_MEMORY;
2252                 }
2253         }
2254         if (permit_interdomain_trust) {
2255                 ret = ldb_request_add_control(req,
2256                                               DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
2257                                               false, NULL);
2258                 if (ret != LDB_SUCCESS) {
2259                         talloc_free(req);
2260                         talloc_free(msg);
2261                         return NT_STATUS_NO_MEMORY;
2262                 }
2263         }
2264         ret = ldb_request_add_control(req,
2265                                       DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2266                                       true, NULL);
2267         if (ret != LDB_SUCCESS) {
2268                 talloc_free(req);
2269                 talloc_free(msg);
2270                 return NT_STATUS_NO_MEMORY;
2271         }
2272
2273         ret = dsdb_autotransaction_request(ldb, req);
2274
2275         if (req->context != NULL) {
2276                 struct ldb_control *control = talloc_get_type_abort(req->context,
2277                                                                     struct ldb_control);
2278                 pwd_stat = talloc_get_type_abort(control->data,
2279                                                  struct dsdb_control_password_change_status);
2280                 talloc_steal(mem_ctx, pwd_stat);
2281         }
2282
2283         talloc_free(req);
2284         talloc_free(msg);
2285
2286         /* Sets the domain info (if requested) */
2287         if (_dominfo != NULL) {
2288                 struct samr_DomInfo1 *dominfo;
2289
2290                 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2291                 if (dominfo == NULL) {
2292                         return NT_STATUS_NO_MEMORY;
2293                 }
2294
2295                 if (pwd_stat != NULL) {
2296                         dominfo->min_password_length     = pwd_stat->domain_data.minPwdLength;
2297                         dominfo->password_properties     = pwd_stat->domain_data.pwdProperties;
2298                         dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2299                         dominfo->max_password_age        = pwd_stat->domain_data.maxPwdAge;
2300                         dominfo->min_password_age        = pwd_stat->domain_data.minPwdAge;
2301                 }
2302
2303                 *_dominfo = dominfo;
2304         }
2305
2306         if (reject_reason != NULL) {
2307                 if (pwd_stat != NULL) {
2308                         *reject_reason = pwd_stat->reject_reason;
2309                 } else {
2310                         *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2311                 }
2312         }
2313
2314         if (pwd_stat != NULL) {
2315                 talloc_free(pwd_stat);
2316         }
2317
2318         if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2319                 const char *errmsg = ldb_errstring(ldb);
2320                 char *endptr = NULL;
2321                 WERROR werr = WERR_GENERAL_FAILURE;
2322                 status = NT_STATUS_UNSUCCESSFUL;
2323                 if (errmsg != NULL) {
2324                         werr = W_ERROR(strtol(errmsg, &endptr, 16));
2325                         DBG_WARNING("%s\n", errmsg);
2326                 }
2327                 if (endptr != errmsg) {
2328                         if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2329                                 status = NT_STATUS_WRONG_PASSWORD;
2330                         }
2331                         if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2332                                 status = NT_STATUS_PASSWORD_RESTRICTION;
2333                         }
2334                 }
2335         } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2336                 /* don't let the caller know if an account doesn't exist */
2337                 status = NT_STATUS_WRONG_PASSWORD;
2338         } else if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2339                 status = NT_STATUS_ACCESS_DENIED;
2340         } else if (ret != LDB_SUCCESS) {
2341                 DEBUG(1, ("Failed to set password on %s: %s\n",
2342                           ldb_dn_get_linearized(msg->dn),
2343                           ldb_errstring(ldb)));
2344                 status = NT_STATUS_UNSUCCESSFUL;
2345         }
2346
2347         return status;
2348 }
2349
2350 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2351                             struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2352                             const DATA_BLOB *new_password,
2353                             const struct samr_Password *lmNewHash,
2354                             const struct samr_Password *ntNewHash,
2355                             const struct samr_Password *lmOldHash,
2356                             const struct samr_Password *ntOldHash,
2357                             enum samPwdChangeReason *reject_reason,
2358                             struct samr_DomInfo1 **_dominfo)
2359 {
2360         return samdb_set_password_internal(ldb, mem_ctx,
2361                             user_dn, domain_dn,
2362                             new_password,
2363                             lmNewHash, ntNewHash,
2364                             lmOldHash, ntOldHash,
2365                             reject_reason, _dominfo,
2366                             false); /* reject trusts */
2367 }
2368
2369 /*
2370  * Sets the user password using plaintext UTF16 (attribute "new_password") or
2371  * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2372  * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2373  * user change or not. The "rejectReason" gives some more information if the
2374  * change failed.
2375  *
2376  * This wrapper function for "samdb_set_password" takes a SID as input rather
2377  * than a user DN.
2378  *
2379  * This call encapsulates a new LDB transaction for changing the password;
2380  * therefore the user hasn't to start a new one.
2381  *
2382  * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2383  *   NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2384  *   NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2385  *   NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2386  */
2387 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2388                                 const struct dom_sid *user_sid,
2389                                 const uint32_t *new_version, /* optional for trusts */
2390                                 const DATA_BLOB *new_password,
2391                                 const struct samr_Password *lmNewHash,
2392                                 const struct samr_Password *ntNewHash,
2393                                 const struct samr_Password *lmOldHash,
2394                                 const struct samr_Password *ntOldHash,
2395                                 enum samPwdChangeReason *reject_reason,
2396                                 struct samr_DomInfo1 **_dominfo) 
2397 {
2398         TALLOC_CTX *frame = talloc_stackframe();
2399         NTSTATUS nt_status;
2400         const char * const user_attrs[] = {
2401                 "userAccountControl",
2402                 "sAMAccountName",
2403                 NULL
2404         };
2405         struct ldb_message *user_msg = NULL;
2406         int ret;
2407         uint32_t uac = 0;
2408
2409         ret = ldb_transaction_start(ldb);
2410         if (ret != LDB_SUCCESS) {
2411                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2412                 TALLOC_FREE(frame);
2413                 return NT_STATUS_TRANSACTION_ABORTED;
2414         }
2415
2416         ret = dsdb_search_one(ldb, frame, &user_msg, ldb_get_default_basedn(ldb),
2417                               LDB_SCOPE_SUBTREE, user_attrs, 0,
2418                               "(&(objectSid=%s)(objectClass=user))",
2419                               ldap_encode_ndr_dom_sid(frame, user_sid));
2420         if (ret != LDB_SUCCESS) {
2421                 ldb_transaction_cancel(ldb);
2422                 DEBUG(3, ("samdb_set_password_sid: SID[%s] not found in samdb %s - %s, "
2423                           "returning NO_SUCH_USER\n",
2424                           dom_sid_string(frame, user_sid),
2425                           ldb_strerror(ret), ldb_errstring(ldb)));
2426                 TALLOC_FREE(frame);
2427                 return NT_STATUS_NO_SUCH_USER;
2428         }
2429
2430         uac = ldb_msg_find_attr_as_uint(user_msg, "userAccountControl", 0);
2431         if (!(uac & UF_ACCOUNT_TYPE_MASK)) {
2432                 ldb_transaction_cancel(ldb);
2433                 DEBUG(1, ("samdb_set_password_sid: invalid "
2434                           "userAccountControl[0x%08X] for SID[%s] DN[%s], "
2435                           "returning NO_SUCH_USER\n",
2436                           (unsigned)uac, dom_sid_string(frame, user_sid),
2437                           ldb_dn_get_linearized(user_msg->dn)));
2438                 TALLOC_FREE(frame);
2439                 return NT_STATUS_NO_SUCH_USER;
2440         }
2441
2442         if (uac & UF_INTERDOMAIN_TRUST_ACCOUNT) {
2443                 const char * const tdo_attrs[] = {
2444                         "trustAuthIncoming",
2445                         "trustDirection",
2446                         NULL
2447                 };
2448                 struct ldb_message *tdo_msg = NULL;
2449                 const char *account_name = NULL;
2450                 uint32_t trust_direction;
2451                 uint32_t i;
2452                 const struct ldb_val *old_val = NULL;
2453                 struct trustAuthInOutBlob old_blob = {};
2454                 uint32_t old_version = 0;
2455                 struct AuthenticationInformation *old_version_a = NULL;
2456                 uint32_t _new_version = 0;
2457                 struct trustAuthInOutBlob new_blob = {};
2458                 struct ldb_val new_val = {};
2459                 struct timeval tv = timeval_current();
2460                 NTTIME now = timeval_to_nttime(&tv);
2461                 enum ndr_err_code ndr_err;
2462
2463                 if (new_password == NULL && ntNewHash == NULL) {
2464                         ldb_transaction_cancel(ldb);
2465                         DEBUG(1, ("samdb_set_password_sid: "
2466                                   "no new password provided "
2467                                   "sAMAccountName for SID[%s] DN[%s], "
2468                                   "returning INVALID_PARAMETER\n",
2469                                   dom_sid_string(frame, user_sid),
2470                                   ldb_dn_get_linearized(user_msg->dn)));
2471                         TALLOC_FREE(frame);
2472                         return NT_STATUS_INVALID_PARAMETER;
2473                 }
2474
2475                 if (new_password != NULL && ntNewHash != NULL) {
2476                         ldb_transaction_cancel(ldb);
2477                         DEBUG(1, ("samdb_set_password_sid: "
2478                                   "two new passwords provided "
2479                                   "sAMAccountName for SID[%s] DN[%s], "
2480                                   "returning INVALID_PARAMETER\n",
2481                                   dom_sid_string(frame, user_sid),
2482                                   ldb_dn_get_linearized(user_msg->dn)));
2483                         TALLOC_FREE(frame);
2484                         return NT_STATUS_INVALID_PARAMETER;
2485                 }
2486
2487                 if (new_password != NULL && (new_password->length % 2)) {
2488                         ldb_transaction_cancel(ldb);
2489                         DEBUG(2, ("samdb_set_password_sid: "
2490                                   "invalid utf16 length (%zu) "
2491                                   "sAMAccountName for SID[%s] DN[%s], "
2492                                   "returning WRONG_PASSWORD\n",
2493                                   new_password->length,
2494                                   dom_sid_string(frame, user_sid),
2495                                   ldb_dn_get_linearized(user_msg->dn)));
2496                         TALLOC_FREE(frame);
2497                         return NT_STATUS_WRONG_PASSWORD;
2498                 }
2499
2500                 if (new_password != NULL && new_password->length >= 500) {
2501                         ldb_transaction_cancel(ldb);
2502                         DEBUG(2, ("samdb_set_password_sid: "
2503                                   "utf16 password too long (%zu) "
2504                                   "sAMAccountName for SID[%s] DN[%s], "
2505                                   "returning WRONG_PASSWORD\n",
2506                                   new_password->length,
2507                                   dom_sid_string(frame, user_sid),
2508                                   ldb_dn_get_linearized(user_msg->dn)));
2509                         TALLOC_FREE(frame);
2510                         return NT_STATUS_WRONG_PASSWORD;
2511                 }
2512
2513                 account_name = ldb_msg_find_attr_as_string(user_msg,
2514                                                         "sAMAccountName", NULL);
2515                 if (account_name == NULL) {
2516                         ldb_transaction_cancel(ldb);
2517                         DEBUG(1, ("samdb_set_password_sid: missing "
2518                                   "sAMAccountName for SID[%s] DN[%s], "
2519                                   "returning NO_SUCH_USER\n",
2520                                   dom_sid_string(frame, user_sid),
2521                                   ldb_dn_get_linearized(user_msg->dn)));
2522                         TALLOC_FREE(frame);
2523                         return NT_STATUS_NO_SUCH_USER;
2524                 }
2525
2526                 nt_status = dsdb_trust_search_tdo_by_type(ldb,
2527                                                           SEC_CHAN_DOMAIN,
2528                                                           account_name,
2529                                                           tdo_attrs,
2530                                                           frame, &tdo_msg);
2531                 if (!NT_STATUS_IS_OK(nt_status)) {
2532                         ldb_transaction_cancel(ldb);
2533                         DEBUG(1, ("samdb_set_password_sid: dsdb_trust_search_tdo "
2534                                   "failed(%s) for sAMAccountName[%s] SID[%s] DN[%s], "
2535                                   "returning INTERNAL_DB_CORRUPTION\n",
2536                                   nt_errstr(nt_status), account_name,
2537                                   dom_sid_string(frame, user_sid),
2538                                   ldb_dn_get_linearized(user_msg->dn)));
2539                         TALLOC_FREE(frame);
2540                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2541                 }
2542
2543                 trust_direction = ldb_msg_find_attr_as_int(tdo_msg,
2544                                                            "trustDirection", 0);
2545                 if (!(trust_direction & LSA_TRUST_DIRECTION_INBOUND)) {
2546                         ldb_transaction_cancel(ldb);
2547                         DEBUG(1, ("samdb_set_password_sid: direction[0x%08X] is "
2548                                   "not inbound for sAMAccountName[%s] "
2549                                   "DN[%s] TDO[%s], "
2550                                   "returning INTERNAL_DB_CORRUPTION\n",
2551                                   (unsigned)trust_direction,
2552                                   account_name,
2553                                   ldb_dn_get_linearized(user_msg->dn),
2554                                   ldb_dn_get_linearized(tdo_msg->dn)));
2555                         TALLOC_FREE(frame);
2556                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2557                 }
2558
2559                 old_val = ldb_msg_find_ldb_val(tdo_msg, "trustAuthIncoming");
2560                 if (old_val != NULL) {
2561                         ndr_err = ndr_pull_struct_blob(old_val, frame, &old_blob,
2562                                         (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
2563                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2564                                 ldb_transaction_cancel(ldb);
2565                                 DEBUG(1, ("samdb_set_password_sid: "
2566                                           "failed(%s) to parse "
2567                                           "trustAuthOutgoing sAMAccountName[%s] "
2568                                           "DN[%s] TDO[%s], "
2569                                           "returning INTERNAL_DB_CORRUPTION\n",
2570                                           ndr_map_error2string(ndr_err),
2571                                           account_name,
2572                                           ldb_dn_get_linearized(user_msg->dn),
2573                                           ldb_dn_get_linearized(tdo_msg->dn)));
2574
2575                                 TALLOC_FREE(frame);
2576                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2577                         }
2578                 }
2579
2580                 for (i = old_blob.current.count; i > 0; i--) {
2581                         struct AuthenticationInformation *a =
2582                                 &old_blob.current.array[i - 1];
2583
2584                         switch (a->AuthType) {
2585                         case TRUST_AUTH_TYPE_NONE:
2586                                 if (i == old_blob.current.count) {
2587                                         /*
2588                                          * remove TRUST_AUTH_TYPE_NONE at the
2589                                          * end
2590                                          */
2591                                         old_blob.current.count--;
2592                                 }
2593                                 break;
2594
2595                         case TRUST_AUTH_TYPE_VERSION:
2596                                 old_version_a = a;
2597                                 old_version = a->AuthInfo.version.version;
2598                                 break;
2599
2600                         case TRUST_AUTH_TYPE_CLEAR:
2601                                 break;
2602
2603                         case TRUST_AUTH_TYPE_NT4OWF:
2604                                 break;
2605                         }
2606                 }
2607
2608                 if (new_version == NULL) {
2609                         _new_version = 0;
2610                         new_version = &_new_version;
2611                 }
2612
2613                 if (old_version_a != NULL && *new_version != (old_version + 1)) {
2614                         old_version_a->LastUpdateTime = now;
2615                         old_version_a->AuthType = TRUST_AUTH_TYPE_NONE;
2616                 }
2617
2618                 new_blob.count = MAX(old_blob.current.count, 2);
2619                 new_blob.current.array = talloc_zero_array(frame,
2620                                                 struct AuthenticationInformation,
2621                                                 new_blob.count);
2622                 if (new_blob.current.array == NULL) {
2623                         ldb_transaction_cancel(ldb);
2624                         TALLOC_FREE(frame);
2625                         return NT_STATUS_NO_MEMORY;
2626                 }
2627                 new_blob.previous.array = talloc_zero_array(frame,
2628                                                 struct AuthenticationInformation,
2629                                                 new_blob.count);
2630                 if (new_blob.current.array == NULL) {
2631                         ldb_transaction_cancel(ldb);
2632                         TALLOC_FREE(frame);
2633                         return NT_STATUS_NO_MEMORY;
2634                 }
2635
2636                 for (i = 0; i < old_blob.current.count; i++) {
2637                         struct AuthenticationInformation *o =
2638                                 &old_blob.current.array[i];
2639                         struct AuthenticationInformation *p =
2640                                 &new_blob.previous.array[i];
2641
2642                         *p = *o;
2643                         new_blob.previous.count++;
2644                 }
2645                 for (; i < new_blob.count; i++) {
2646                         struct AuthenticationInformation *pi =
2647                                 &new_blob.previous.array[i];
2648
2649                         if (i == 0) {
2650                                 /*
2651                                  * new_blob.previous is still empty so
2652                                  * we'll do new_blob.previous = new_blob.current
2653                                  * below.
2654                                  */
2655                                 break;
2656                         }
2657
2658                         pi->LastUpdateTime = now;
2659                         pi->AuthType = TRUST_AUTH_TYPE_NONE;
2660                         new_blob.previous.count++;
2661                 }
2662
2663                 for (i = 0; i < new_blob.count; i++) {
2664                         struct AuthenticationInformation *ci =
2665                                 &new_blob.current.array[i];
2666
2667                         ci->LastUpdateTime = now;
2668                         switch (i) {
2669                         case 0:
2670                                 if (ntNewHash != NULL) {
2671                                         ci->AuthType = TRUST_AUTH_TYPE_NT4OWF;
2672                                         ci->AuthInfo.nt4owf.password = *ntNewHash;
2673                                         break;
2674                                 }
2675
2676                                 ci->AuthType = TRUST_AUTH_TYPE_CLEAR;
2677                                 ci->AuthInfo.clear.size = new_password->length;
2678                                 ci->AuthInfo.clear.password = new_password->data;
2679                                 break;
2680                         case 1:
2681                                 ci->AuthType = TRUST_AUTH_TYPE_VERSION;
2682                                 ci->AuthInfo.version.version = *new_version;
2683                                 break;
2684                         default:
2685                                 ci->AuthType = TRUST_AUTH_TYPE_NONE;
2686                                 break;
2687                         }
2688
2689                         new_blob.current.count++;
2690                 }
2691
2692                 if (new_blob.previous.count == 0) {
2693                         TALLOC_FREE(new_blob.previous.array);
2694                         new_blob.previous = new_blob.current;
2695                 }
2696
2697                 ndr_err = ndr_push_struct_blob(&new_val, frame, &new_blob,
2698                                 (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
2699                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2700                         ldb_transaction_cancel(ldb);
2701                         DEBUG(1, ("samdb_set_password_sid: "
2702                                   "failed(%s) to generate "
2703                                   "trustAuthOutgoing sAMAccountName[%s] "
2704                                   "DN[%s] TDO[%s], "
2705                                   "returning UNSUCCESSFUL\n",
2706                                   ndr_map_error2string(ndr_err),
2707                                   account_name,
2708                                   ldb_dn_get_linearized(user_msg->dn),
2709                                   ldb_dn_get_linearized(tdo_msg->dn)));
2710                         TALLOC_FREE(frame);
2711                         return NT_STATUS_UNSUCCESSFUL;
2712                 }
2713
2714                 tdo_msg->num_elements = 0;
2715                 TALLOC_FREE(tdo_msg->elements);
2716
2717                 ret = ldb_msg_add_empty(tdo_msg, "trustAuthIncoming",
2718                                         LDB_FLAG_MOD_REPLACE, NULL);
2719                 if (ret != LDB_SUCCESS) {
2720                         ldb_transaction_cancel(ldb);
2721                         TALLOC_FREE(frame);
2722                         return NT_STATUS_NO_MEMORY;
2723                 }
2724                 ret = ldb_msg_add_value(tdo_msg, "trustAuthIncoming",
2725                                         &new_val, NULL);
2726                 if (ret != LDB_SUCCESS) {
2727                         ldb_transaction_cancel(ldb);
2728                         TALLOC_FREE(frame);
2729                         return NT_STATUS_NO_MEMORY;
2730                 }
2731
2732                 ret = ldb_modify(ldb, tdo_msg);
2733                 if (ret != LDB_SUCCESS) {
2734                         nt_status = dsdb_ldb_err_to_ntstatus(ret);
2735                         ldb_transaction_cancel(ldb);
2736                         DEBUG(1, ("samdb_set_password_sid: "
2737                                   "failed to replace "
2738                                   "trustAuthOutgoing sAMAccountName[%s] "
2739                                   "DN[%s] TDO[%s], "
2740                                   "%s - %s\n",
2741                                   account_name,
2742                                   ldb_dn_get_linearized(user_msg->dn),
2743                                   ldb_dn_get_linearized(tdo_msg->dn),
2744                                   nt_errstr(nt_status), ldb_errstring(ldb)));
2745                         TALLOC_FREE(frame);
2746                         return nt_status;
2747                 }
2748         }
2749
2750         nt_status = samdb_set_password_internal(ldb, mem_ctx,
2751                                                 user_msg->dn, NULL,
2752                                                 new_password,
2753                                                 lmNewHash, ntNewHash,
2754                                                 lmOldHash, ntOldHash,
2755                                                 reject_reason, _dominfo,
2756                                                 true); /* permit trusts */
2757         if (!NT_STATUS_IS_OK(nt_status)) {
2758                 ldb_transaction_cancel(ldb);
2759                 TALLOC_FREE(frame);
2760                 return nt_status;
2761         }
2762
2763         ret = ldb_transaction_commit(ldb);
2764         if (ret != LDB_SUCCESS) {
2765                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2766                          ldb_dn_get_linearized(user_msg->dn),
2767                          ldb_errstring(ldb)));
2768                 TALLOC_FREE(frame);
2769                 return NT_STATUS_TRANSACTION_ABORTED;
2770         }
2771
2772         TALLOC_FREE(frame);
2773         return NT_STATUS_OK;
2774 }
2775
2776
2777 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
2778                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
2779 {
2780         struct ldb_message *msg;
2781         struct ldb_dn *basedn;
2782         char *sidstr;
2783         int ret;
2784
2785         sidstr = dom_sid_string(mem_ctx, sid);
2786         NT_STATUS_HAVE_NO_MEMORY(sidstr);
2787
2788         /* We might have to create a ForeignSecurityPrincipal, even if this user
2789          * is in our own domain */
2790
2791         msg = ldb_msg_new(sidstr);
2792         if (msg == NULL) {
2793                 talloc_free(sidstr);
2794                 return NT_STATUS_NO_MEMORY;
2795         }
2796
2797         ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2798                                 ldb_get_default_basedn(sam_ctx),
2799                                 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2800                                 &basedn);
2801         if (ret != LDB_SUCCESS) {
2802                 DEBUG(0, ("Failed to find DN for "
2803                           "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2804                 talloc_free(sidstr);
2805                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2806         }
2807
2808         /* add core elements to the ldb_message for the alias */
2809         msg->dn = basedn;
2810         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2811                 talloc_free(sidstr);
2812                 return NT_STATUS_NO_MEMORY;
2813         }
2814
2815         ret = ldb_msg_add_string(msg, "objectClass",
2816                                  "foreignSecurityPrincipal");
2817         if (ret != LDB_SUCCESS) {
2818                 talloc_free(sidstr);
2819                 return NT_STATUS_NO_MEMORY;
2820         }
2821
2822         /* create the alias */
2823         ret = ldb_add(sam_ctx, msg);
2824         if (ret != LDB_SUCCESS) {
2825                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2826                          "record %s: %s\n", 
2827                          ldb_dn_get_linearized(msg->dn),
2828                          ldb_errstring(sam_ctx)));
2829                 talloc_free(sidstr);
2830                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2831         }
2832
2833         *ret_dn = talloc_steal(mem_ctx, msg->dn);
2834         talloc_free(sidstr);
2835
2836         return NT_STATUS_OK;
2837 }
2838
2839
2840 /*
2841   Find the DN of a domain, assuming it to be a dotted.dns name
2842 */
2843
2844 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) 
2845 {
2846         unsigned int i;
2847         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2848         const char *binary_encoded;
2849         const char * const *split_realm;
2850         struct ldb_dn *dn;
2851
2852         if (!tmp_ctx) {
2853                 return NULL;
2854         }
2855
2856         split_realm = (const char * const *)str_list_make(tmp_ctx, dns_domain, ".");
2857         if (!split_realm) {
2858                 talloc_free(tmp_ctx);
2859                 return NULL;
2860         }
2861         dn = ldb_dn_new(mem_ctx, ldb, NULL);
2862         for (i=0; split_realm[i]; i++) {
2863                 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2864                 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2865                         DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2866                                   binary_encoded, ldb_dn_get_linearized(dn)));
2867                         talloc_free(tmp_ctx);
2868                         return NULL;
2869                 }
2870         }
2871         if (!ldb_dn_validate(dn)) {
2872                 DEBUG(2, ("Failed to validated DN %s\n",
2873                           ldb_dn_get_linearized(dn)));
2874                 talloc_free(tmp_ctx);
2875                 return NULL;
2876         }
2877         talloc_free(tmp_ctx);
2878         return dn;
2879 }
2880
2881
2882 /*
2883   Find the DNS equivalent of a DN, in dotted DNS form
2884 */
2885 char *samdb_dn_to_dns_domain(TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
2886 {
2887         int i, num_components = ldb_dn_get_comp_num(dn);
2888         char *dns_name = talloc_strdup(mem_ctx, "");
2889         if (dns_name == NULL) {
2890                 return NULL;
2891         }
2892
2893         for (i=0; i<num_components; i++) {
2894                 const struct ldb_val *v = ldb_dn_get_component_val(dn, i);
2895                 char *s;
2896                 if (v == NULL) {
2897                         talloc_free(dns_name);
2898                         return NULL;
2899                 }
2900                 s = talloc_asprintf_append_buffer(dns_name, "%*.*s.",
2901                                                   (int)v->length, (int)v->length, (char *)v->data);
2902                 if (s == NULL) {
2903                         talloc_free(dns_name);
2904                         return NULL;
2905                 }
2906                 dns_name = s;
2907         }
2908
2909         /* remove the last '.' */
2910         if (dns_name[0] != 0) {
2911                 dns_name[strlen(dns_name)-1] = 0;
2912         }
2913
2914         return dns_name;
2915 }
2916
2917 /*
2918   Find the DNS _msdcs name for a given NTDS GUID. The resulting DNS
2919   name is based on the forest DNS name
2920 */
2921 char *samdb_ntds_msdcs_dns_name(struct ldb_context *samdb,
2922                                 TALLOC_CTX *mem_ctx,
2923                                 const struct GUID *ntds_guid)
2924 {
2925         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2926         const char *guid_str;
2927         struct ldb_dn *forest_dn;
2928         const char *dnsforest;
2929         char *ret;
2930
2931         guid_str = GUID_string(tmp_ctx, ntds_guid);
2932         if (guid_str == NULL) {
2933                 talloc_free(tmp_ctx);
2934                 return NULL;
2935         }
2936         forest_dn = ldb_get_root_basedn(samdb);
2937         if (forest_dn == NULL) {
2938                 talloc_free(tmp_ctx);
2939                 return NULL;
2940         }
2941         dnsforest = samdb_dn_to_dns_domain(tmp_ctx, forest_dn);
2942         if (dnsforest == NULL) {
2943                 talloc_free(tmp_ctx);
2944                 return NULL;
2945         }
2946         ret = talloc_asprintf(mem_ctx, "%s._msdcs.%s", guid_str, dnsforest);
2947         talloc_free(tmp_ctx);
2948         return ret;
2949 }
2950
2951
2952 /*
2953   Find the DN of a domain, be it the netbios or DNS name 
2954 */
2955 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
2956                                   const char *domain_name) 
2957 {
2958         const char * const domain_ref_attrs[] = {
2959                 "ncName", NULL
2960         };
2961         const char * const domain_ref2_attrs[] = {
2962                 NULL
2963         };
2964         struct ldb_result *res_domain_ref;
2965         char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2966         /* find the domain's DN */
2967         int ret_domain = ldb_search(ldb, mem_ctx,
2968                                             &res_domain_ref, 
2969                                             samdb_partitions_dn(ldb, mem_ctx), 
2970                                             LDB_SCOPE_ONELEVEL, 
2971                                             domain_ref_attrs,
2972                                             "(&(nETBIOSName=%s)(objectclass=crossRef))", 
2973                                             escaped_domain);
2974         if (ret_domain != LDB_SUCCESS) {
2975                 return NULL;
2976         }
2977
2978         if (res_domain_ref->count == 0) {
2979                 ret_domain = ldb_search(ldb, mem_ctx,
2980                                                 &res_domain_ref, 
2981                                                 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2982                                                 LDB_SCOPE_BASE,
2983                                                 domain_ref2_attrs,
2984                                                 "(objectclass=domain)");
2985                 if (ret_domain != LDB_SUCCESS) {
2986                         return NULL;
2987                 }
2988
2989                 if (res_domain_ref->count == 1) {
2990                         return res_domain_ref->msgs[0]->dn;
2991                 }
2992                 return NULL;
2993         }
2994
2995         if (res_domain_ref->count > 1) {
2996                 DEBUG(0,("Found %d records matching domain [%s]\n", 
2997                          ret_domain, domain_name));
2998                 return NULL;
2999         }
3000
3001         return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
3002
3003 }
3004
3005
3006 /*
3007   use a GUID to find a DN
3008  */
3009 int dsdb_find_dn_by_guid(struct ldb_context *ldb, 
3010                          TALLOC_CTX *mem_ctx,
3011                          const struct GUID *guid,
3012                          uint32_t dsdb_flags,
3013                          struct ldb_dn **dn)
3014 {
3015         int ret;
3016         struct ldb_result *res;
3017         const char *attrs[] = { NULL };
3018         char *guid_str = GUID_string(mem_ctx, guid);
3019
3020         if (!guid_str) {
3021                 return ldb_operr(ldb);
3022         }
3023
3024         ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3025                           DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3026                           DSDB_SEARCH_SHOW_EXTENDED_DN |
3027                           DSDB_SEARCH_ONE_ONLY | dsdb_flags,
3028                           "objectGUID=%s", guid_str);
3029         talloc_free(guid_str);
3030         if (ret != LDB_SUCCESS) {
3031                 return ret;
3032         }
3033
3034         *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
3035         talloc_free(res);
3036
3037         return LDB_SUCCESS;
3038 }
3039
3040 /*
3041   use a DN to find a GUID with a given attribute name
3042  */
3043 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
3044                               struct ldb_dn *dn, const char *attribute,
3045                               struct GUID *guid)
3046 {
3047         int ret;
3048         struct ldb_result *res;
3049         const char *attrs[2];
3050         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3051
3052         attrs[0] = attribute;
3053         attrs[1] = NULL;
3054
3055         ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
3056                              DSDB_SEARCH_SHOW_DELETED |
3057                              DSDB_SEARCH_SHOW_RECYCLED);
3058         if (ret != LDB_SUCCESS) {
3059                 talloc_free(tmp_ctx);
3060                 return ret;
3061         }
3062         if (res->count < 1) {
3063                 talloc_free(tmp_ctx);
3064                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3065         }
3066         *guid = samdb_result_guid(res->msgs[0], attribute);
3067         talloc_free(tmp_ctx);
3068         return LDB_SUCCESS;
3069 }
3070
3071 /*
3072   use a DN to find a GUID
3073  */
3074 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
3075                          struct ldb_dn *dn, struct GUID *guid)
3076 {
3077         return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
3078 }
3079
3080
3081
3082 /*
3083  adds the given GUID to the given ldb_message. This value is added
3084  for the given attr_name (may be either "objectGUID" or "parentGUID").
3085  */
3086 int dsdb_msg_add_guid(struct ldb_message *msg,
3087                 struct GUID *guid,
3088                 const char *attr_name)
3089 {
3090         int ret;
3091         struct ldb_val v;
3092         NTSTATUS status;
3093         TALLOC_CTX *tmp_ctx =  talloc_init("dsdb_msg_add_guid");
3094
3095         status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
3096         if (!NT_STATUS_IS_OK(status)) {
3097                 ret = LDB_ERR_OPERATIONS_ERROR;
3098                 goto done;
3099         }
3100
3101         ret = ldb_msg_add_steal_value(msg, attr_name, &v);
3102         if (ret != LDB_SUCCESS) {
3103                 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
3104                                          attr_name));
3105                 goto done;
3106         }
3107
3108         ret = LDB_SUCCESS;
3109
3110 done:
3111         talloc_free(tmp_ctx);
3112         return ret;
3113
3114 }
3115
3116
3117 /*
3118   use a DN to find a SID
3119  */
3120 int dsdb_find_sid_by_dn(struct ldb_context *ldb, 
3121                         struct ldb_dn *dn, struct dom_sid *sid)
3122 {
3123         int ret;
3124         struct ldb_result *res;
3125         const char *attrs[] = { "objectSid", NULL };
3126         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3127         struct dom_sid *s;
3128
3129         ZERO_STRUCTP(sid);
3130
3131         ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
3132                              DSDB_SEARCH_SHOW_DELETED |
3133                              DSDB_SEARCH_SHOW_RECYCLED);
3134         if (ret != LDB_SUCCESS) {
3135                 talloc_free(tmp_ctx);
3136                 return ret;
3137         }
3138         if (res->count < 1) {
3139                 talloc_free(tmp_ctx);
3140                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3141         }
3142         s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
3143         if (s == NULL) {
3144                 talloc_free(tmp_ctx);
3145                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3146         }
3147         *sid = *s;
3148         talloc_free(tmp_ctx);
3149         return LDB_SUCCESS;
3150 }
3151
3152 /*
3153   use a SID to find a DN
3154  */
3155 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
3156                         TALLOC_CTX *mem_ctx,
3157                         struct dom_sid *sid, struct ldb_dn **dn)
3158 {
3159         int ret;
3160         struct ldb_result *res;
3161         const char *attrs[] = { NULL };
3162         char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
3163
3164         if (!sid_str) {
3165                 return ldb_operr(ldb);
3166         }
3167
3168         ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3169                           DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3170                           DSDB_SEARCH_SHOW_EXTENDED_DN |
3171                           DSDB_SEARCH_ONE_ONLY,
3172                           "objectSid=%s", sid_str);
3173         talloc_free(sid_str);
3174         if (ret != LDB_SUCCESS) {
3175                 return ret;
3176         }
3177
3178         *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
3179         talloc_free(res);
3180
3181         return LDB_SUCCESS;
3182 }
3183
3184 /*
3185   load a repsFromTo blob list for a given partition GUID
3186   attr must be "repsFrom" or "repsTo"
3187  */
3188 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3189                      const char *attr, struct repsFromToBlob **r, uint32_t *count)
3190 {
3191         const char *attrs[] = { attr, NULL };
3192         struct ldb_result *res = NULL;
3193         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3194         unsigned int i;
3195         struct ldb_message_element *el;
3196         int ret;
3197
3198         *r = NULL;
3199         *count = 0;
3200
3201         ret = dsdb_search_dn(sam_ctx, tmp_ctx, &res, dn, attrs, 0);
3202         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
3203                 /* partition hasn't been replicated yet */
3204                 return WERR_OK;
3205         }
3206         if (ret != LDB_SUCCESS) {
3207                 DEBUG(0,("dsdb_loadreps: failed to read partition object: %s\n", ldb_errstring(sam_ctx)));
3208                 talloc_free(tmp_ctx);
3209                 return WERR_DS_DRA_INTERNAL_ERROR;
3210         }
3211
3212         el = ldb_msg_find_element(res->msgs[0], attr);
3213         if (el == NULL) {
3214                 /* it's OK to be empty */
3215                 talloc_free(tmp_ctx);
3216                 return WERR_OK;
3217         }
3218
3219         *count = el->num_values;
3220         *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
3221         if (*r == NULL) {
3222                 talloc_free(tmp_ctx);
3223                 return WERR_DS_DRA_INTERNAL_ERROR;
3224         }
3225
3226         for (i=0; i<(*count); i++) {
3227                 enum ndr_err_code ndr_err;
3228                 ndr_err = ndr_pull_struct_blob(&el->values[i], 
3229                                                mem_ctx, 
3230                                                &(*r)[i], 
3231                                                (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3232                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3233                         talloc_free(tmp_ctx);
3234                         return WERR_DS_DRA_INTERNAL_ERROR;
3235                 }
3236         }
3237
3238         talloc_free(tmp_ctx);
3239         
3240         return WERR_OK;
3241 }
3242
3243 /*
3244   save the repsFromTo blob list for a given partition GUID
3245   attr must be "repsFrom" or "repsTo"
3246  */
3247 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3248                      const char *attr, struct repsFromToBlob *r, uint32_t count)
3249 {
3250         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3251         struct ldb_message *msg;
3252         struct ldb_message_element *el;
3253         unsigned int i;
3254
3255         msg = ldb_msg_new(tmp_ctx);
3256         msg->dn = dn;
3257         if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
3258                 goto failed;
3259         }
3260
3261         el->values = talloc_array(msg, struct ldb_val, count);
3262         if (!el->values) {
3263                 goto failed;
3264         }
3265
3266         for (i=0; i<count; i++) {
3267                 struct ldb_val v;
3268                 enum ndr_err_code ndr_err;
3269
3270                 ndr_err = ndr_push_struct_blob(&v, tmp_ctx, 
3271                                                &r[i], 
3272                                                (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3273                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3274                         goto failed;
3275                 }
3276
3277                 el->num_values++;
3278                 el->values[i] = v;
3279         }
3280
3281         if (dsdb_modify(sam_ctx, msg, 0) != LDB_SUCCESS) {
3282                 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
3283                 goto failed;
3284         }
3285
3286         talloc_free(tmp_ctx);
3287         
3288         return WERR_OK;
3289
3290 failed:
3291         talloc_free(tmp_ctx);
3292         return WERR_DS_DRA_INTERNAL_ERROR;
3293 }
3294
3295
3296 /*
3297   load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
3298   object for a partition
3299  */
3300 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
3301                                 uint64_t *uSN, uint64_t *urgent_uSN)
3302 {
3303         struct ldb_request *req;
3304         int ret;
3305         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3306         struct dsdb_control_current_partition *p_ctrl;
3307         struct ldb_result *res;
3308
3309         res = talloc_zero(tmp_ctx, struct ldb_result);
3310         if (!res) {
3311                 talloc_free(tmp_ctx);
3312                 return ldb_oom(ldb);
3313         }
3314
3315         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3316                                    ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
3317                                    LDB_SCOPE_BASE,
3318                                    NULL, NULL,
3319                                    NULL,
3320                                    res, ldb_search_default_callback,
3321                                    NULL);
3322         if (ret != LDB_SUCCESS) {
3323                 talloc_free(tmp_ctx);
3324                 return ret;
3325         }
3326
3327         p_ctrl = talloc(req, struct dsdb_control_current_partition);
3328         if (p_ctrl == NULL) {
3329                 talloc_free(tmp_ctx);
3330                 return ldb_oom(ldb);
3331         }
3332         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
3333         p_ctrl->dn = dn;
3334         
3335         ret = ldb_request_add_control(req,
3336                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3337                                       false, p_ctrl);
3338         if (ret != LDB_SUCCESS) {
3339                 talloc_free(tmp_ctx);
3340                 return ret;
3341         }
3342         
3343         /* Run the new request */
3344         ret = ldb_request(ldb, req);
3345         
3346         if (ret == LDB_SUCCESS) {
3347                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3348         }
3349
3350         if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
3351                 /* it hasn't been created yet, which means
3352                    an implicit value of zero */
3353                 *uSN = 0;
3354                 talloc_free(tmp_ctx);
3355                 return LDB_SUCCESS;
3356         }
3357
3358         if (ret != LDB_SUCCESS) {
3359                 talloc_free(tmp_ctx);
3360                 return ret;
3361         }
3362
3363         if (res->count < 1) {
3364                 *uSN = 0;
3365                 if (urgent_uSN) {
3366                         *urgent_uSN = 0;
3367                 }
3368         } else {
3369                 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
3370                 if (urgent_uSN) {
3371                         *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
3372                 }
3373         }
3374
3375         talloc_free(tmp_ctx);
3376
3377         return LDB_SUCCESS;     
3378 }
3379
3380 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
3381                                                    const struct drsuapi_DsReplicaCursor2 *c2)
3382 {
3383         return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
3384 }
3385
3386 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
3387                                     const struct drsuapi_DsReplicaCursor *c2)
3388 {
3389         return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
3390 }
3391
3392
3393 /*
3394   see if a computer identified by its invocationId is a RODC
3395 */
3396 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
3397 {
3398         /* 1) find the DN for this servers NTDSDSA object
3399            2) search for the msDS-isRODC attribute
3400            3) if not present then not a RODC
3401            4) if present and TRUE then is a RODC
3402         */
3403         struct ldb_dn *config_dn;
3404         const char *attrs[] = { "msDS-isRODC", NULL };
3405         int ret;
3406         struct ldb_result *res;
3407         TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
3408
3409         config_dn = ldb_get_config_basedn(sam_ctx);
3410         if (!config_dn) {
3411                 talloc_free(tmp_ctx);
3412                 return ldb_operr(sam_ctx);
3413         }
3414
3415         ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
3416                           DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
3417
3418         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
3419                 *is_rodc = false;
3420                 talloc_free(tmp_ctx);
3421                 return LDB_SUCCESS;
3422         }
3423
3424         if (ret != LDB_SUCCESS) {
3425                 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
3426                          GUID_string(tmp_ctx, objectGUID)));
3427                 *is_rodc = false;
3428                 talloc_free(tmp_ctx);
3429                 return ret;
3430         }
3431
3432         ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
3433         *is_rodc = (ret == 1);
3434
3435         talloc_free(tmp_ctx);
3436         return LDB_SUCCESS;
3437 }
3438
3439
3440 /*
3441   see if we are a RODC
3442 */
3443 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
3444 {
3445         const struct GUID *objectGUID;
3446         int ret;
3447         bool *cached;
3448
3449         /* see if we have a cached copy */
3450         cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
3451         if (cached) {
3452                 *am_rodc = *cached;
3453                 return LDB_SUCCESS;
3454         }
3455
3456         objectGUID = samdb_ntds_objectGUID(sam_ctx);
3457         if (!objectGUID) {
3458                 return ldb_operr(sam_ctx);
3459         }
3460
3461         ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
3462         if (ret != LDB_SUCCESS) {
3463                 return ret;
3464         }
3465
3466         cached = talloc(sam_ctx, bool);
3467         if (cached == NULL) {
3468                 return ldb_oom(sam_ctx);
3469         }
3470         *cached = *am_rodc;
3471
3472         ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
3473         if (ret != LDB_SUCCESS) {
3474                 talloc_free(cached);
3475                 return ldb_operr(sam_ctx);
3476         }
3477
3478         return LDB_SUCCESS;
3479 }
3480
3481 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
3482 {
3483         TALLOC_CTX *tmp_ctx;
3484         bool *cached;
3485
3486         tmp_ctx = talloc_new(ldb);
3487         if (tmp_ctx == NULL) {
3488                 goto failed;
3489         }
3490
3491         cached = talloc(tmp_ctx, bool);
3492         if (!cached) {
3493                 goto failed;
3494         }
3495
3496         *cached = am_rodc;
3497         if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
3498                 goto failed;
3499         }
3500
3501         talloc_steal(ldb, cached);
3502         talloc_free(tmp_ctx);
3503         return true;
3504
3505 failed:
3506         DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
3507         talloc_free(tmp_ctx);
3508         return false;
3509 }
3510
3511
3512 /*
3513  * return NTDSSiteSettings options. See MS-ADTS 7.1.1.2.2.1.1
3514  * flags are DS_NTDSSETTINGS_OPT_*
3515  */
3516 int samdb_ntds_site_settings_options(struct ldb_context *ldb_ctx,
3517                                         uint32_t *options)
3518 {
3519         int rc;
3520         TALLOC_CTX *tmp_ctx;
3521         struct ldb_result *res;
3522         struct ldb_dn *site_dn;
3523         const char *attrs[] = { "options", NULL };
3524
3525         tmp_ctx = talloc_new(ldb_ctx);
3526         if (tmp_ctx == NULL)
3527                 goto failed;
3528
3529         /* Retrieve the site dn for the ldb that we
3530          * have open.  This is our local site.
3531          */
3532         site_dn = samdb_server_site_dn(ldb_ctx, tmp_ctx);
3533         if (site_dn == NULL)
3534                 goto failed;
3535
3536         /* Perform a one level (child) search from the local
3537          * site distinguided name.   We're looking for the
3538          * "options" attribute within the nTDSSiteSettings
3539          * object
3540          */
3541         rc = ldb_search(ldb_ctx, tmp_ctx, &res, site_dn,
3542                         LDB_SCOPE_ONELEVEL, attrs,
3543                         "objectClass=nTDSSiteSettings");
3544
3545         if (rc != LDB_SUCCESS || res->count != 1)
3546                 goto failed;
3547
3548         *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
3549
3550         talloc_free(tmp_ctx);
3551
3552         return LDB_SUCCESS;
3553
3554 failed:
3555         DEBUG(1,("Failed to find our NTDS Site Settings options in ldb!\n"));
3556         talloc_free(tmp_ctx);
3557         return ldb_error(ldb_ctx, LDB_ERR_NO_SUCH_OBJECT, __func__);
3558 }
3559
3560 /*
3561   return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1 
3562
3563   flags are DS_NTDS_OPTION_*
3564 */
3565 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
3566 {
3567         TALLOC_CTX *tmp_ctx;
3568         const char *attrs[] = { "options", NULL };
3569         int ret;
3570         struct ldb_result *res;
3571
3572         tmp_ctx = talloc_new(ldb);
3573         if (tmp_ctx == NULL) {
3574                 goto failed;
3575         }
3576
3577         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
3578         if (ret != LDB_SUCCESS) {
3579                 goto failed;
3580         }
3581
3582         if (res->count != 1) {
3583                 goto failed;
3584         }
3585
3586         *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
3587
3588         talloc_free(tmp_ctx);
3589
3590         return LDB_SUCCESS;
3591
3592 failed:
3593         DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
3594         talloc_free(tmp_ctx);
3595         return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3596 }
3597
3598 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3599 {
3600         const char *attrs[] = { "objectCategory", NULL };
3601         int ret;
3602         struct ldb_result *res;
3603
3604         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
3605         if (ret != LDB_SUCCESS) {
3606                 goto failed;
3607         }
3608
3609         if (res->count != 1) {
3610                 goto failed;
3611         }
3612
3613         return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
3614
3615 failed:
3616         DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3617         return NULL;
3618 }
3619
3620 /*
3621  * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3622  * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3623  */
3624 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3625 {
3626         char **tokens, *ret;
3627         size_t i;
3628
3629         tokens = str_list_make(mem_ctx, cn, " -_");
3630         if (tokens == NULL || tokens[0] == NULL) {
3631                 return NULL;
3632         }
3633
3634         /* "tolower()" and "toupper()" should also work properly on 0x00 */
3635         tokens[0][0] = tolower(tokens[0][0]);
3636         for (i = 1; tokens[i] != NULL; i++)
3637                 tokens[i][0] = toupper(tokens[i][0]);
3638
3639         ret = talloc_strdup(mem_ctx, tokens[0]);
3640         for (i = 1; tokens[i] != NULL; i++)
3641                 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3642
3643         talloc_free(tokens);
3644
3645         return ret;
3646 }
3647
3648 /*
3649  * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3650  */
3651 int dsdb_functional_level(struct ldb_context *ldb)
3652 {
3653         int *domainFunctionality =
3654                 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3655         if (!domainFunctionality) {
3656                 /* this is expected during initial provision */
3657                 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3658                 return DS_DOMAIN_FUNCTION_2000;
3659         }
3660         return *domainFunctionality;
3661 }
3662
3663 /*
3664  * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3665  */
3666 int dsdb_forest_functional_level(struct ldb_context *ldb)
3667 {
3668         int *forestFunctionality =
3669                 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3670         if (!forestFunctionality) {
3671                 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3672                 return DS_DOMAIN_FUNCTION_2000;
3673         }
3674         return *forestFunctionality;
3675 }
3676
3677 /*
3678   set a GUID in an extended DN structure
3679  */
3680 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3681 {
3682         struct ldb_val v;
3683         NTSTATUS status;
3684         int ret;
3685
3686         status = GUID_to_ndr_blob(guid, dn, &v);
3687         if (!NT_STATUS_IS_OK(status)) {
3688                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3689         }
3690
3691         ret = ldb_dn_set_extended_component(dn, component_name, &v);
3692         data_blob_free(&v);
3693         return ret;
3694 }
3695
3696 /*
3697   return a GUID from a extended DN structure
3698  */
3699 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3700 {
3701         const struct ldb_val *v;
3702
3703         v = ldb_dn_get_extended_component(dn, component_name);
3704         if (v == NULL) {
3705                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3706         }
3707
3708         return GUID_from_ndr_blob(v, guid);
3709 }
3710
3711 /*
3712   return a uint64_t from a extended DN structure
3713  */
3714 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3715 {
3716         const struct ldb_val *v;
3717
3718         v = ldb_dn_get_extended_component(dn, component_name);
3719         if (v == NULL) {
3720                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3721         }
3722
3723         {
3724                 char s[v->length+1];
3725                 memcpy(s, v->data, v->length);
3726                 s[v->length] = 0;
3727
3728                 *val = strtoull(s, NULL, 0);
3729         }
3730         return NT_STATUS_OK;
3731 }
3732
3733 /*
3734   return a NTTIME from a extended DN structure
3735  */
3736 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3737 {
3738         return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3739 }
3740
3741 /*
3742   return a uint32_t from a extended DN structure
3743  */
3744 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3745 {
3746         const struct ldb_val *v;
3747
3748         v = ldb_dn_get_extended_component(dn, component_name);
3749         if (v == NULL) {
3750                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3751         }
3752
3753         {
3754                 char s[v->length + 1];
3755                 memcpy(s, v->data, v->length);
3756                 s[v->length] = 0;
3757                 *val = strtoul(s, NULL, 0);
3758         }
3759
3760         return NT_STATUS_OK;
3761 }
3762
3763 /*
3764   return a dom_sid from a extended DN structure
3765  */
3766 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3767 {
3768         const struct ldb_val *sid_blob;
3769         enum ndr_err_code ndr_err;
3770
3771         sid_blob = ldb_dn_get_extended_component(dn, component_name);
3772         if (!sid_blob) {
3773                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3774         }
3775
3776         ndr_err = ndr_pull_struct_blob_all_noalloc(sid_blob, sid,
3777                                                    (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3778         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3779                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3780                 return status;
3781         }
3782
3783         return NT_STATUS_OK;
3784 }
3785
3786
3787 /*
3788   return RMD_FLAGS directly from a ldb_dn
3789   returns 0 if not found
3790  */
3791 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3792 {
3793         const struct ldb_val *v;
3794         char buf[32];
3795         v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3796         if (!v || v->length > sizeof(buf)-1) return 0;
3797         strncpy(buf, (const char *)v->data, v->length);
3798         buf[v->length] = 0;
3799         return strtoul(buf, NULL, 10);
3800 }
3801
3802 /*
3803   return RMD_FLAGS directly from a ldb_val for a DN
3804   returns 0 if RMD_FLAGS is not found
3805  */
3806 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3807 {
3808         const char *p;
3809         uint32_t flags;
3810         char *end;
3811
3812         if (val->length < 13) {
3813                 return 0;
3814         }
3815         p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
3816         if (!p) {
3817                 return 0;
3818         }
3819         flags = strtoul(p+11, &end, 10);
3820         if (!end || *end != '>') {
3821                 /* it must end in a > */
3822                 return 0;
3823         }
3824         return flags;
3825 }
3826
3827 /*
3828   return true if a ldb_val containing a DN in storage form is deleted
3829  */
3830 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3831 {
3832         return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3833 }
3834
3835 /*
3836   return true if a ldb_val containing a DN in storage form is
3837   in the upgraded w2k3 linked attribute format
3838  */
3839 bool dsdb_dn_is_upgraded_link_val(const struct ldb_val *val)
3840 {
3841         return memmem(val->data, val->length, "<RMD_VERSION=", 13) != NULL;
3842 }
3843
3844 /*
3845   return a DN for a wellknown GUID
3846  */
3847 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3848                       struct ldb_dn *nc_root, const char *wk_guid,
3849                       struct ldb_dn **wkguid_dn)
3850 {
3851         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3852         const char *attrs[] = { NULL };
3853         int ret;
3854         struct ldb_dn *dn;
3855         struct ldb_result *res;
3856
3857         /* construct the magic WKGUID DN */
3858         dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3859                             wk_guid, ldb_dn_get_linearized(nc_root));
3860         if (!wkguid_dn) {
3861                 talloc_free(tmp_ctx);
3862                 return ldb_operr(samdb);
3863         }
3864
3865         ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
3866                              DSDB_SEARCH_SHOW_DELETED |
3867                              DSDB_SEARCH_SHOW_RECYCLED);
3868         if (ret != LDB_SUCCESS) {
3869                 talloc_free(tmp_ctx);
3870                 return ret;
3871         }
3872
3873         (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3874         talloc_free(tmp_ctx);
3875         return LDB_SUCCESS;
3876 }
3877
3878
3879 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3880 {
3881         return ldb_dn_compare(*dn1, *dn2);
3882 }
3883
3884 /*
3885   find a NC root given a DN within the NC
3886  */
3887 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3888                       struct ldb_dn **nc_root)
3889 {
3890         const char *root_attrs[] = { "namingContexts", NULL };
3891         TALLOC_CTX *tmp_ctx;
3892         int ret;
3893         struct ldb_message_element *el;
3894         struct ldb_result *root_res;
3895         unsigned int i;
3896         struct ldb_dn **nc_dns;
3897
3898         tmp_ctx = talloc_new(samdb);
3899         if (tmp_ctx == NULL) {
3900                 return ldb_oom(samdb);
3901         }
3902
3903         ret = ldb_search(samdb, tmp_ctx, &root_res,
3904                          ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3905         if (ret != LDB_SUCCESS || root_res->count == 0) {
3906                 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3907                 talloc_free(tmp_ctx);
3908                 return ret;
3909         }
3910
3911         el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3912         if ((el == NULL) || (el->num_values < 3)) {
3913                 struct ldb_message *tmp_msg;
3914
3915                 DEBUG(5,("dsdb_find_nc_root: Finding a valid 'namingContexts' element in the RootDSE failed. Using a temporary list."));
3916
3917                 /* This generates a temporary list of NCs in order to let the
3918                  * provisioning work. */
3919                 tmp_msg = ldb_msg_new(tmp_ctx);
3920                 if (tmp_msg == NULL) {
3921                         talloc_free(tmp_ctx);
3922                         return ldb_oom(samdb);
3923                 }
3924                 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
3925                                                ldb_dn_alloc_linearized(tmp_msg, ldb_get_schema_basedn(samdb)));
3926                 if (ret != LDB_SUCCESS) {
3927                         talloc_free(tmp_ctx);
3928                         return ret;
3929                 }
3930                 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
3931                                                ldb_dn_alloc_linearized(tmp_msg, ldb_get_config_basedn(samdb)));
3932                 if (ret != LDB_SUCCESS) {
3933                         talloc_free(tmp_ctx);
3934                         return ret;
3935                 }
3936                 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
3937                                                ldb_dn_alloc_linearized(tmp_msg, ldb_get_default_basedn(samdb)));
3938                 if (ret != LDB_SUCCESS) {
3939                         talloc_free(tmp_ctx);
3940                         return ret;
3941                 }
3942                 el = &tmp_msg->elements[0];
3943         }
3944
3945        nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3946        if (!nc_dns) {
3947                talloc_free(tmp_ctx);
3948                return ldb_oom(samdb);
3949        }
3950
3951        for (i=0; i<el->num_values; i++) {
3952                nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3953                if (nc_dns[i] == NULL) {
3954                        talloc_free(tmp_ctx);
3955                        return ldb_operr(samdb);
3956                }
3957        }
3958
3959        TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3960
3961        for (i=0; i<el->num_values; i++) {
3962                if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3963                        (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3964                        talloc_free(tmp_ctx);
3965                        return LDB_SUCCESS;
3966                }
3967        }
3968
3969        talloc_free(tmp_ctx);
3970        return ldb_error(samdb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3971 }
3972
3973
3974 /*
3975   find the deleted objects DN for any object, by looking for the NC
3976   root, then looking up the wellknown GUID
3977  */
3978 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3979                                 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3980                                 struct ldb_dn **do_dn)
3981 {
3982         struct ldb_dn *nc_root;
3983         int ret;
3984
3985         ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3986         if (ret != LDB_SUCCESS) {
3987                 return ret;
3988         }
3989
3990         ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3991         talloc_free(nc_root);
3992         return ret;
3993 }
3994
3995 /*
3996   return the tombstoneLifetime, in days
3997  */
3998 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3999 {
4000         struct ldb_dn *dn;
4001         dn = ldb_get_config_basedn(ldb);
4002         if (!dn) {
4003                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4004         }
4005         dn = ldb_dn_copy(ldb, dn);
4006         if (!dn) {
4007                 return ldb_operr(ldb);
4008         }
4009         /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
4010          be a wellknown GUID for this */
4011         if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
4012                 talloc_free(dn);
4013                 return ldb_operr(ldb);
4014         }
4015
4016         *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
4017         talloc_free(dn);
4018         return LDB_SUCCESS;
4019 }
4020
4021 /*
4022   compare a ldb_val to a string case insensitively
4023  */
4024 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
4025 {
4026         size_t len = strlen(s);
4027         int ret;
4028         if (len > v->length) return 1;
4029         ret = strncasecmp(s, (const char *)v->data, v->length);
4030         if (ret != 0) return ret;
4031         if (v->length > len && v->data[len] != 0) {
4032                 return -1;
4033         }
4034         return 0;
4035 }
4036
4037
4038 /*
4039   load the UDV for a partition in v2 format
4040   The list is returned sorted, and with our local cursor added
4041  */
4042 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
4043                      struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
4044 {
4045         static const char *attrs[] = { "replUpToDateVector", NULL };
4046         struct ldb_result *r;
4047         const struct ldb_val *ouv_value;
4048         unsigned int i;
4049         int ret;
4050         uint64_t highest_usn = 0;
4051         const struct GUID *our_invocation_id;
4052         static const struct timeval tv1970;
4053         NTTIME nt1970 = timeval_to_nttime(&tv1970);
4054
4055         ret = dsdb_search_dn(samdb, mem_ctx, &r, dn, attrs, DSDB_SEARCH_SHOW_RECYCLED|DSDB_SEARCH_SHOW_DELETED);
4056         if (ret != LDB_SUCCESS) {
4057                 return ret;
4058         }
4059
4060         ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
4061         if (ouv_value) {
4062                 enum ndr_err_code ndr_err;
4063                 struct replUpToDateVectorBlob ouv;
4064
4065                 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
4066                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
4067                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4068                         talloc_free(r);
4069                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
4070                 }
4071                 if (ouv.version != 2) {
4072                         /* we always store as version 2, and
4073                          * replUpToDateVector is not replicated
4074                          */
4075                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
4076                 }
4077
4078                 *count = ouv.ctr.ctr2.count;
4079                 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
4080         } else {
4081                 *count = 0;
4082                 *cursors = NULL;
4083         }
4084
4085         talloc_free(r);
4086
4087         our_invocation_id = samdb_ntds_invocation_id(samdb);
4088         if (!our_invocation_id) {
4089                 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
4090                 talloc_free(*cursors);
4091                 return ldb_operr(samdb);
4092         }
4093
4094         ret = ldb_sequence_number(samdb, LDB_SEQ_HIGHEST_SEQ, &highest_usn);
4095         if (ret != LDB_SUCCESS) {
4096                 /* nothing to add - this can happen after a vampire */
4097                 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
4098                 return LDB_SUCCESS;
4099         }
4100
4101         for (i=0; i<*count; i++) {
4102                 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
4103                         (*cursors)[i].highest_usn = highest_usn;
4104                         (*cursors)[i].last_sync_success = nt1970;
4105                         TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
4106                         return LDB_SUCCESS;
4107                 }
4108         }
4109
4110         (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
4111         if (! *cursors) {
4112                 return ldb_oom(samdb);
4113         }
4114
4115         (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
4116         (*cursors)[*count].highest_usn = highest_usn;
4117         (*cursors)[*count].last_sync_success = nt1970;
4118         (*count)++;
4119
4120         TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
4121
4122         return LDB_SUCCESS;
4123 }
4124
4125 /*
4126   load the UDV for a partition in version 1 format
4127   The list is returned sorted, and with our local cursor added
4128  */
4129 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
4130                      struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
4131 {
4132         struct drsuapi_DsReplicaCursor2 *v2;
4133         uint32_t i;
4134         int ret;
4135
4136         ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
4137         if (ret != LDB_SUCCESS) {
4138                 return ret;
4139         }
4140
4141         if (*count == 0) {
4142                 talloc_free(v2);
4143                 *cursors = NULL;
4144                 return LDB_SUCCESS;
4145         }
4146
4147         *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
4148         if (*cursors == NULL) {
4149                 talloc_free(v2);
4150                 return ldb_oom(samdb);
4151         }
4152
4153         for (i=0; i<*count; i++) {
4154                 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
4155                 (*cursors)[i].highest_usn = v2[i].highest_usn;
4156         }
4157         talloc_free(v2);
4158         return LDB_SUCCESS;
4159 }
4160
4161 /*
4162   add a set of controls to a ldb_request structure based on a set of
4163   flags. See util.h for a list of available flags
4164  */
4165 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
4166 {
4167         int ret;
4168         if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
4169                 struct ldb_search_options_control *options;
4170                 /* Using the phantom root control allows us to search all partitions */
4171                 options = talloc(req, struct ldb_search_options_control);
4172                 if (options == NULL) {
4173                         return LDB_ERR_OPERATIONS_ERROR;
4174                 }
4175                 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
4176
4177                 ret = ldb_request_add_control(req,
4178                                               LDB_CONTROL_SEARCH_OPTIONS_OID,
4179                                               true, options);
4180                 if (ret != LDB_SUCCESS) {
4181                         return ret;
4182                 }
4183         }
4184
4185         if (dsdb_flags & DSDB_SEARCH_NO_GLOBAL_CATALOG) {
4186                 ret = ldb_request_add_control(req,
4187                                               DSDB_CONTROL_NO_GLOBAL_CATALOG,
4188                                               false, NULL);
4189                 if (ret != LDB_SUCCESS) {
4190                         return ret;
4191                 }
4192         }
4193
4194         if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
4195                 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
4196                 if (ret != LDB_SUCCESS) {
4197                         return ret;
4198                 }
4199         }
4200
4201         if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
4202                 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
4203                 if (ret != LDB_SUCCESS) {
4204                         return ret;
4205                 }
4206         }
4207
4208         if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
4209                 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, false, NULL);
4210                 if (ret != LDB_SUCCESS) {
4211                         return ret;
4212                 }
4213         }
4214
4215         if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
4216                 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
4217                 if (!extended_ctrl) {
4218                         return LDB_ERR_OPERATIONS_ERROR;
4219                 }
4220                 extended_ctrl->type = 1;
4221
4222                 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
4223                 if (ret != LDB_SUCCESS) {
4224                         return ret;
4225                 }
4226         }
4227
4228         if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
4229                 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
4230                 if (ret != LDB_SUCCESS) {
4231                         return ret;
4232                 }
4233         }
4234
4235         if (dsdb_flags & DSDB_MODIFY_RELAX) {
4236                 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
4237                 if (ret != LDB_SUCCESS) {
4238                         return ret;
4239                 }
4240         }
4241
4242         if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
4243                 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
4244                 if (ret != LDB_SUCCESS) {
4245                         return ret;
4246                 }
4247         }
4248
4249         if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
4250                 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
4251                 if (ret != LDB_SUCCESS) {
4252                         return ret;
4253                 }
4254         }
4255
4256         if (dsdb_flags & DSDB_TREE_DELETE) {
4257                 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
4258                 if (ret != LDB_SUCCESS) {
4259                         return ret;
4260                 }
4261         }
4262
4263         if (dsdb_flags & DSDB_PROVISION) {
4264                 ret = ldb_request_add_control(req, LDB_CONTROL_PROVISION_OID, false, NULL);
4265                 if (ret != LDB_SUCCESS) {
4266                         return ret;
4267                 }
4268         }
4269
4270         /* This is a special control to bypass the password_hash module for use in pdb_samba4 for Samba3 upgrades */
4271         if (dsdb_flags & DSDB_BYPASS_PASSWORD_HASH) {
4272                 ret = ldb_request_add_control(req, DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID, true, NULL);
4273                 if (ret != LDB_SUCCESS) {
4274                         return ret;
4275                 }
4276         }
4277
4278         if (dsdb_flags & DSDB_PASSWORD_BYPASS_LAST_SET) {
4279                 /* 
4280                  * This must not be critical, as it will only be
4281                  * handled (and need to be handled) if the other
4282                  * attributes in the request bring password_hash into
4283                  * action
4284                  */
4285                 ret = ldb_request_add_control(req, DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID, false, NULL);
4286                 if (ret != LDB_SUCCESS) {
4287                         return ret;
4288                 }
4289         }
4290
4291         if (dsdb_flags & DSDB_REPLMD_VANISH_LINKS) {
4292                 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS, true, NULL);
4293                 if (ret != LDB_SUCCESS) {
4294                         return ret;
4295                 }
4296         }
4297
4298         if (dsdb_flags & DSDB_MODIFY_PARTIAL_REPLICA) {
4299                 ret = ldb_request_add_control(req, DSDB_CONTROL_PARTIAL_REPLICA, false, NULL);
4300                 if (ret != LDB_SUCCESS) {
4301                         return ret;
4302                 }
4303         }
4304
4305         return LDB_SUCCESS;
4306 }
4307
4308 /*
4309   an add with a set of controls
4310 */
4311 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
4312              uint32_t dsdb_flags)
4313 {
4314         struct ldb_request *req;
4315         int ret;
4316
4317         ret = ldb_build_add_req(&req, ldb, ldb,
4318                                 message,
4319                                 NULL,
4320                                 NULL,
4321                                 ldb_op_default_callback,
4322                                 NULL);
4323
4324         if (ret != LDB_SUCCESS) return ret;
4325
4326         ret = dsdb_request_add_controls(req, dsdb_flags);
4327         if (ret != LDB_SUCCESS) {
4328                 talloc_free(req);
4329                 return ret;
4330         }
4331
4332         ret = dsdb_autotransaction_request(ldb, req);
4333
4334         talloc_free(req);
4335         return ret;
4336 }
4337
4338 /*
4339   a modify with a set of controls
4340 */
4341 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
4342                 uint32_t dsdb_flags)
4343 {
4344         struct ldb_request *req;
4345         int ret;
4346
4347         ret = ldb_build_mod_req(&req, ldb, ldb,
4348                                 message,
4349                                 NULL,
4350                                 NULL,
4351                                 ldb_op_default_callback,
4352                                 NULL);
4353
4354         if (ret != LDB_SUCCESS) return ret;
4355
4356         ret = dsdb_request_add_controls(req, dsdb_flags);
4357         if (ret != LDB_SUCCESS) {
4358                 talloc_free(req);
4359                 return ret;
4360         }
4361
4362         ret = dsdb_autotransaction_request(ldb, req);
4363
4364         talloc_free(req);
4365         return ret;
4366 }
4367
4368 /*
4369   a delete with a set of flags
4370 */
4371 int dsdb_delete(struct ldb_context *ldb, struct ldb_dn *dn,
4372                 uint32_t dsdb_flags)
4373 {
4374         struct ldb_request *req;
4375         int ret;
4376
4377         ret = ldb_build_del_req(&req, ldb, ldb,
4378                                 dn,
4379                                 NULL,
4380                                 NULL,
4381                                 ldb_op_default_callback,
4382                                 NULL);
4383
4384         if (ret != LDB_SUCCESS) return ret;
4385
4386         ret = dsdb_request_add_controls(req, dsdb_flags);
4387         if (ret != LDB_SUCCESS) {
4388                 talloc_free(req);
4389                 return ret;
4390         }
4391
4392         ret = dsdb_autotransaction_request(ldb, req);
4393
4394         talloc_free(req);
4395         return ret;
4396 }
4397
4398 /*
4399   like dsdb_modify() but set all the element flags to
4400   LDB_FLAG_MOD_REPLACE
4401  */
4402 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
4403 {
4404         unsigned int i;
4405
4406         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
4407         for (i=0;i<msg->num_elements;i++) {
4408                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
4409         }
4410
4411         return dsdb_modify(ldb, msg, dsdb_flags);
4412 }
4413
4414
4415 /*
4416   search for attrs on one DN, allowing for dsdb_flags controls
4417  */
4418 int dsdb_search_dn(struct ldb_context *ldb,
4419                    TALLOC_CTX *mem_ctx,
4420                    struct ldb_result **_result,
4421                    struct ldb_dn *basedn,
4422                    const char * const *attrs,
4423                    uint32_t dsdb_flags)
4424 {
4425         int ret;
4426         struct ldb_request *req;
4427         struct ldb_result *res;
4428
4429         res = talloc_zero(mem_ctx, struct ldb_result);
4430         if (!res) {
4431                 return ldb_oom(ldb);
4432         }
4433
4434         ret = ldb_build_search_req(&req, ldb, res,
4435                                    basedn,
4436                                    LDB_SCOPE_BASE,
4437                                    NULL,
4438                                    attrs,
4439                                    NULL,
4440                                    res,
4441                                    ldb_search_default_callback,
4442                                    NULL);
4443         if (ret != LDB_SUCCESS) {
4444                 talloc_free(res);
4445                 return ret;
4446         }
4447
4448         ret = dsdb_request_add_controls(req, dsdb_flags);
4449         if (ret != LDB_SUCCESS) {
4450                 talloc_free(res);
4451                 return ret;
4452         }
4453
4454         ret = ldb_request(ldb, req);
4455         if (ret == LDB_SUCCESS) {
4456                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
4457         }
4458
4459         talloc_free(req);
4460         if (ret != LDB_SUCCESS) {
4461                 talloc_free(res);
4462                 return ret;
4463         }
4464
4465         *_result = res;
4466         return LDB_SUCCESS;
4467 }
4468
4469 /*
4470   search for attrs on one DN, by the GUID of the DN, allowing for
4471   dsdb_flags controls
4472  */
4473 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
4474                            TALLOC_CTX *mem_ctx,
4475                            struct ldb_result **_result,
4476                            const struct GUID *guid,
4477                            const char * const *attrs,
4478                            uint32_t dsdb_flags)
4479 {
4480         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
4481         struct ldb_dn *dn;
4482         int ret;
4483
4484         dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
4485         if (dn == NULL) {
4486                 talloc_free(tmp_ctx);
4487                 return ldb_oom(ldb);
4488         }
4489
4490         ret = dsdb_search_dn(ldb, mem_ctx, _result, dn, attrs, dsdb_flags);
4491         talloc_free(tmp_ctx);
4492         return ret;
4493 }
4494
4495 /*
4496   general search with dsdb_flags for controls
4497  */
4498 int dsdb_search(struct ldb_context *ldb,
4499                 TALLOC_CTX *mem_ctx,
4500                 struct ldb_result **_result,
4501                 struct ldb_dn *basedn,
4502                 enum ldb_scope scope,
4503                 const char * const *attrs,
4504                 uint32_t dsdb_flags,
4505                 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
4506 {
4507         int ret;
4508         struct ldb_request *req;
4509         struct ldb_result *res;
4510         va_list ap;
4511         char *expression = NULL;
4512         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
4513
4514         /* cross-partitions searches with a basedn break multi-domain support */
4515         SMB_ASSERT(basedn == NULL || (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) == 0);
4516
4517         res = talloc_zero(tmp_ctx, struct ldb_result);
4518         if (!res) {
4519                 talloc_free(tmp_ctx);
4520                 return ldb_oom(ldb);
4521         }
4522
4523         if (exp_fmt) {
4524                 va_start(ap, exp_fmt);
4525                 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
4526                 va_end(ap);
4527
4528                 if (!expression) {
4529                         talloc_free(tmp_ctx);
4530                         return ldb_oom(ldb);
4531                 }
4532         }
4533
4534         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
4535                                    basedn,
4536                                    scope,
4537                                    expression,
4538                                    attrs,
4539                                    NULL,
4540                                    res,
4541                                    ldb_search_default_callback,
4542                                    NULL);
4543         if (ret != LDB_SUCCESS) {
4544                 talloc_free(tmp_ctx);
4545                 return ret;
4546         }
4547
4548         ret = dsdb_request_add_controls(req, dsdb_flags);
4549         if (ret != LDB_SUCCESS) {
4550                 talloc_free(tmp_ctx);
4551                 ldb_reset_err_string(ldb);
4552                 return ret;
4553         }
4554
4555         ret = ldb_request(ldb, req);
4556         if (ret == LDB_SUCCESS) {
4557                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
4558         }
4559
4560         if (ret != LDB_SUCCESS) {
4561                 talloc_free(tmp_ctx);
4562                 return ret;
4563         }
4564
4565         if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
4566                 if (res->count == 0) {
4567                         talloc_free(tmp_ctx);
4568                         ldb_reset_err_string(ldb);
4569                         return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4570                 }
4571                 if (res->count != 1) {
4572                         talloc_free(tmp_ctx);
4573                         ldb_reset_err_string(ldb);
4574                         return LDB_ERR_CONSTRAINT_VIOLATION;
4575                 }
4576         }
4577
4578         *_result = talloc_steal(mem_ctx, res);
4579         talloc_free(tmp_ctx);
4580
4581         return LDB_SUCCESS;
4582 }
4583
4584
4585 /*
4586   general search with dsdb_flags for controls
4587   returns exactly 1 record or an error
4588  */
4589 int dsdb_search_one(struct ldb_context *ldb,
4590                     TALLOC_CTX *mem_ctx,
4591                     struct ldb_message **msg,
4592                     struct ldb_dn *basedn,
4593                     enum ldb_scope scope,
4594                     const char * const *attrs,
4595                     uint32_t dsdb_flags,
4596                     const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
4597 {
4598         int ret;
4599         struct ldb_result *res;
4600         va_list ap;
4601         char *expression = NULL;
4602         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
4603
4604         dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
4605
4606         res = talloc_zero(tmp_ctx, struct ldb_result);
4607         if (!res) {
4608                 talloc_free(tmp_ctx);
4609                 return ldb_oom(ldb);
4610         }
4611
4612         if (exp_fmt) {
4613                 va_start(ap, exp_fmt);
4614                 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
4615                 va_end(ap);
4616
4617                 if (!expression) {
4618                         talloc_free(tmp_ctx);
4619                         return ldb_oom(ldb);
4620                 }
4621                 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
4622                                   dsdb_flags, "%s", expression);
4623         } else {
4624                 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
4625                                   dsdb_flags, NULL);
4626         }
4627
4628         if (ret != LDB_SUCCESS) {
4629                 talloc_free(tmp_ctx);
4630                 return ret;
4631         }
4632
4633         *msg = talloc_steal(mem_ctx, res->msgs[0]);
4634         talloc_free(tmp_ctx);
4635
4636         return LDB_SUCCESS;
4637 }
4638
4639 /* returns back the forest DNS name */
4640 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
4641 {
4642         const char *forest_name = ldb_dn_canonical_string(mem_ctx,
4643                                                           ldb_get_root_basedn(ldb));
4644         char *p;
4645
4646         if (forest_name == NULL) {
4647                 return NULL;
4648         }
4649
4650         p = strchr(forest_name, '/');
4651         if (p) {
4652                 *p = '\0';
4653         }
4654
4655         return forest_name;
4656 }
4657
4658 /* returns back the default domain DNS name */
4659 const char *samdb_default_domain_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
4660 {
4661         const char *domain_name = ldb_dn_canonical_string(mem_ctx,
4662                                                           ldb_get_default_basedn(ldb));
4663         char *p;
4664
4665         if (domain_name == NULL) {
4666                 return NULL;
4667         }
4668
4669         p = strchr(domain_name, '/');
4670         if (p) {
4671                 *p = '\0';
4672         }
4673
4674         return domain_name;
4675 }
4676
4677 /*
4678    validate that an DSA GUID belongs to the specified user sid.
4679    The user SID must be a domain controller account (either RODC or
4680    RWDC)
4681  */
4682 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
4683                            const struct GUID *dsa_guid,
4684                            const struct dom_sid *sid)
4685 {
4686         /* strategy:
4687             - find DN of record with the DSA GUID in the
4688               configuration partition (objectGUID)
4689             - remove "NTDS Settings" component from DN
4690             - do a base search on that DN for serverReference with
4691               extended-dn enabled
4692             - extract objectSid from resulting serverReference
4693               attribute
4694             - check this sid matches the sid argument
4695         */
4696         struct ldb_dn *config_dn;
4697         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
4698         struct ldb_message *msg;
4699         const char *attrs1[] = { NULL };
4700         const char *attrs2[] = { "serverReference", NULL };
4701         int ret;
4702         struct ldb_dn *dn, *account_dn;
4703         struct dom_sid sid2;
4704         NTSTATUS status;
4705
4706         config_dn = ldb_get_config_basedn(ldb);
4707
4708         ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
4709                               attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
4710         if (ret != LDB_SUCCESS) {
4711                 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
4712                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4713                 talloc_free(tmp_ctx);
4714                 return ldb_operr(ldb);
4715         }
4716         dn = msg->dn;
4717
4718         if (!ldb_dn_remove_child_components(dn, 1)) {
4719                 talloc_free(tmp_ctx);
4720                 return ldb_operr(ldb);
4721         }
4722
4723         ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
4724                               attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
4725                               "(objectClass=server)");
4726         if (ret != LDB_SUCCESS) {
4727                 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
4728                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4729                 talloc_free(tmp_ctx);
4730                 return ldb_operr(ldb);
4731         }
4732
4733         account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
4734         if (account_dn == NULL) {
4735                 DEBUG(1,(__location__ ": Failed to find account dn "
4736                          "(serverReference) for %s, parent of DSA with "
4737                          "objectGUID %s, sid %s\n",
4738                          ldb_dn_get_linearized(msg->dn),
4739                          GUID_string(tmp_ctx, dsa_guid),
4740                          dom_sid_string(tmp_ctx, sid)));
4741                 talloc_free(tmp_ctx);
4742                 return ldb_operr(ldb);
4743         }
4744
4745         status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
4746         if (!NT_STATUS_IS_OK(status)) {
4747                 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
4748                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4749                 talloc_free(tmp_ctx);
4750                 return ldb_operr(ldb);
4751         }
4752
4753         if (!dom_sid_equal(sid, &sid2)) {
4754                 /* someone is trying to spoof another account */
4755                 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
4756                          GUID_string(tmp_ctx, dsa_guid),
4757                          dom_sid_string(tmp_ctx, sid),
4758                          dom_sid_string(tmp_ctx, &sid2)));
4759                 talloc_free(tmp_ctx);
4760                 return ldb_operr(ldb);
4761         }
4762
4763         talloc_free(tmp_ctx);
4764         return LDB_SUCCESS;
4765 }
4766
4767 static const char * const secret_attributes[] = {
4768         DSDB_SECRET_ATTRIBUTES,
4769         NULL
4770 };
4771
4772 /*
4773   check if the attribute belongs to the RODC filtered attribute set
4774   Note that attributes that are in the filtered attribute set are the
4775   ones that _are_ always sent to a RODC
4776 */
4777 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4778 {
4779         /* they never get secret attributes */
4780         if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4781                 return false;
4782         }
4783
4784         /* they do get non-secret critical attributes */
4785         if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4786                 return true;
4787         }
4788
4789         /* they do get non-secret attributes marked as being in the FAS  */
4790         if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4791                 return true;
4792         }
4793
4794         /* other attributes are denied */
4795         return false;
4796 }
4797
4798 /* return fsmo role dn and role owner dn for a particular role*/
4799 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4800                                struct ldb_context *ldb,
4801                                uint32_t role,
4802                                struct ldb_dn **fsmo_role_dn,
4803                                struct ldb_dn **role_owner_dn)
4804 {
4805         int ret;
4806         switch (role) {
4807         case DREPL_NAMING_MASTER:
4808                 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
4809                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4810                 if (ret != LDB_SUCCESS) {
4811                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4812                                  ldb_errstring(ldb)));
4813                         talloc_free(tmp_ctx);
4814                         return WERR_DS_DRA_INTERNAL_ERROR;
4815                 }
4816                 break;
4817         case DREPL_INFRASTRUCTURE_MASTER:
4818                 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4819                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4820                 if (ret != LDB_SUCCESS) {
4821                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4822                                  ldb_errstring(ldb)));
4823                         talloc_free(tmp_ctx);
4824                         return WERR_DS_DRA_INTERNAL_ERROR;
4825                 }
4826                 break;
4827         case DREPL_RID_MASTER:
4828                 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4829                 if (ret != LDB_SUCCESS) {
4830                         DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4831                         talloc_free(tmp_ctx);
4832                         return WERR_DS_DRA_INTERNAL_ERROR;
4833                 }
4834
4835                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4836                 if (ret != LDB_SUCCESS) {
4837                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4838                                  ldb_errstring(ldb)));
4839                         talloc_free(tmp_ctx);
4840                         return WERR_DS_DRA_INTERNAL_ERROR;
4841                 }
4842                 break;
4843         case DREPL_SCHEMA_MASTER:
4844                 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4845                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4846                 if (ret != LDB_SUCCESS) {
4847                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4848                                  ldb_errstring(ldb)));
4849                         talloc_free(tmp_ctx);
4850                         return WERR_DS_DRA_INTERNAL_ERROR;
4851                 }
4852                 break;
4853         case DREPL_PDC_MASTER:
4854                 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4855                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4856                 if (ret != LDB_SUCCESS) {
4857                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4858                                  ldb_errstring(ldb)));
4859                         talloc_free(tmp_ctx);
4860                         return WERR_DS_DRA_INTERNAL_ERROR;
4861                 }
4862                 break;
4863         default:
4864                 return WERR_DS_DRA_INTERNAL_ERROR;
4865         }
4866         return WERR_OK;
4867 }
4868
4869 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
4870                                     TALLOC_CTX *mem_ctx,
4871                                     struct ldb_dn *server_dn)
4872 {
4873         int ldb_ret;
4874         struct ldb_result *res = NULL;
4875         const char * const attrs[] = { "dNSHostName", NULL};
4876
4877         ldb_ret = ldb_search(ldb, mem_ctx, &res,
4878                              server_dn,
4879                              LDB_SCOPE_BASE,
4880                              attrs, NULL);
4881         if (ldb_ret != LDB_SUCCESS) {
4882                 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
4883                           ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
4884                 return NULL;
4885         }
4886
4887         return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
4888 }
4889
4890 /*
4891   returns true if an attribute is in the filter,
4892   false otherwise, provided that attribute value is provided with the expression
4893 */
4894 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
4895                              const char *attr)
4896 {
4897        unsigned int i;
4898        switch (tree->operation) {
4899        case LDB_OP_AND:
4900        case LDB_OP_OR:
4901                for (i=0;i<tree->u.list.num_elements;i++) {
4902                        if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
4903                                                        attr))
4904                                return true;
4905                }
4906                return false;
4907        case LDB_OP_NOT:
4908                return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
4909        case LDB_OP_EQUALITY:
4910        case LDB_OP_GREATER:
4911        case LDB_OP_LESS:
4912        case LDB_OP_APPROX:
4913                if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
4914                        return true;
4915                }
4916                return false;
4917        case LDB_OP_SUBSTRING:
4918                if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
4919                        return true;
4920                }
4921                return false;
4922        case LDB_OP_PRESENT:
4923                /* (attrname=*) is not filtered out */
4924                return false;
4925        case LDB_OP_EXTENDED:
4926                if (tree->u.extended.attr &&
4927                    ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
4928                        return true;
4929                }
4930                return false;
4931        }
4932        return false;
4933 }
4934
4935 bool is_attr_in_list(const char * const * attrs, const char *attr)
4936 {
4937         unsigned int i;
4938
4939         for (i = 0; attrs[i]; i++) {
4940                 if (ldb_attr_cmp(attrs[i], attr) == 0)
4941                         return true;
4942         }
4943
4944         return false;
4945 }
4946
4947 int dsdb_werror_at(struct ldb_context *ldb, int ldb_ecode, WERROR werr,
4948                    const char *location, const char *func,
4949                    const char *reason)
4950 {
4951         if (reason == NULL) {
4952                 reason = win_errstr(werr);
4953         }
4954         ldb_asprintf_errstring(ldb, "%08X: %s at %s:%s",
4955                                W_ERROR_V(werr), reason, location, func);
4956         return ldb_ecode;
4957 }
4958
4959 /*
4960   map an ldb error code to an approximate NTSTATUS code
4961  */
4962 NTSTATUS dsdb_ldb_err_to_ntstatus(int err)
4963 {
4964         switch (err) {
4965         case LDB_SUCCESS:
4966                 return NT_STATUS_OK;
4967
4968         case LDB_ERR_PROTOCOL_ERROR:
4969                 return NT_STATUS_DEVICE_PROTOCOL_ERROR;
4970
4971         case LDB_ERR_TIME_LIMIT_EXCEEDED:
4972                 return NT_STATUS_IO_TIMEOUT;
4973
4974         case LDB_ERR_SIZE_LIMIT_EXCEEDED:
4975                 return NT_STATUS_BUFFER_TOO_SMALL;
4976
4977         case LDB_ERR_COMPARE_FALSE:
4978         case LDB_ERR_COMPARE_TRUE:
4979                 return NT_STATUS_REVISION_MISMATCH;
4980
4981         case LDB_ERR_AUTH_METHOD_NOT_SUPPORTED:
4982                 return NT_STATUS_NOT_SUPPORTED;
4983
4984         case LDB_ERR_STRONG_AUTH_REQUIRED:
4985         case LDB_ERR_CONFIDENTIALITY_REQUIRED:
4986         case LDB_ERR_SASL_BIND_IN_PROGRESS:
4987         case LDB_ERR_INAPPROPRIATE_AUTHENTICATION:
4988         case LDB_ERR_INVALID_CREDENTIALS:
4989         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
4990         case LDB_ERR_UNWILLING_TO_PERFORM:
4991                 return NT_STATUS_ACCESS_DENIED;
4992
4993         case LDB_ERR_NO_SUCH_OBJECT:
4994                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4995
4996         case LDB_ERR_REFERRAL:
4997         case LDB_ERR_NO_SUCH_ATTRIBUTE:
4998                 return NT_STATUS_NOT_FOUND;
4999
5000         case LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION:
5001                 return NT_STATUS_NOT_SUPPORTED;
5002
5003         case LDB_ERR_ADMIN_LIMIT_EXCEEDED:
5004                 return NT_STATUS_BUFFER_TOO_SMALL;
5005
5006         case LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE:
5007         case LDB_ERR_INAPPROPRIATE_MATCHING:
5008         case LDB_ERR_CONSTRAINT_VIOLATION:
5009         case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX:
5010         case LDB_ERR_INVALID_DN_SYNTAX:
5011         case LDB_ERR_NAMING_VIOLATION:
5012         case LDB_ERR_OBJECT_CLASS_VIOLATION:
5013         case LDB_ERR_NOT_ALLOWED_ON_NON_LEAF:
5014         case LDB_ERR_NOT_ALLOWED_ON_RDN:
5015                 return NT_STATUS_INVALID_PARAMETER;
5016
5017         case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
5018         case LDB_ERR_ENTRY_ALREADY_EXISTS:
5019                 return NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS;
5020
5021         case LDB_ERR_BUSY:
5022                 return NT_STATUS_NETWORK_BUSY;
5023
5024         case LDB_ERR_ALIAS_PROBLEM:
5025         case LDB_ERR_ALIAS_DEREFERENCING_PROBLEM:
5026         case LDB_ERR_UNAVAILABLE:
5027         case LDB_ERR_LOOP_DETECT:
5028         case LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED:
5029         case LDB_ERR_AFFECTS_MULTIPLE_DSAS:
5030         case LDB_ERR_OTHER:
5031         case LDB_ERR_OPERATIONS_ERROR:
5032                 break;
5033         }
5034         return NT_STATUS_UNSUCCESSFUL;
5035 }
5036
5037
5038 /*
5039   create a new naming context that will hold a partial replica
5040  */
5041 int dsdb_create_partial_replica_NC(struct ldb_context *ldb,  struct ldb_dn *dn)
5042 {
5043         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
5044         struct ldb_message *msg;
5045         int ret;
5046
5047         msg = ldb_msg_new(tmp_ctx);
5048         if (msg == NULL) {
5049                 talloc_free(tmp_ctx);
5050                 return ldb_oom(ldb);
5051         }
5052
5053         msg->dn = dn;
5054         ret = ldb_msg_add_string(msg, "objectClass", "top");
5055         if (ret != LDB_SUCCESS) {
5056                 talloc_free(tmp_ctx);
5057                 return ldb_oom(ldb);
5058         }
5059
5060         /* [MS-DRSR] implies that we should only add the 'top'
5061          * objectclass, but that would cause lots of problems with our
5062          * objectclass code as top is not structural, so we add
5063          * 'domainDNS' as well to keep things sane. We're expecting
5064          * this new NC to be of objectclass domainDNS after
5065          * replication anyway
5066          */
5067         ret = ldb_msg_add_string(msg, "objectClass", "domainDNS");
5068         if (ret != LDB_SUCCESS) {
5069                 talloc_free(tmp_ctx);
5070                 return ldb_oom(ldb);
5071         }
5072
5073         ret = ldb_msg_add_fmt(msg, "instanceType", "%u",
5074                               INSTANCE_TYPE_IS_NC_HEAD|
5075                               INSTANCE_TYPE_NC_ABOVE|
5076                               INSTANCE_TYPE_UNINSTANT);
5077         if (ret != LDB_SUCCESS) {
5078                 talloc_free(tmp_ctx);
5079                 return ldb_oom(ldb);
5080         }
5081
5082         ret = dsdb_add(ldb, msg, DSDB_MODIFY_PARTIAL_REPLICA);
5083         if (ret != LDB_SUCCESS && ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5084                 DEBUG(0,("Failed to create new NC for %s - %s (%s)\n",
5085                          ldb_dn_get_linearized(dn),
5086                          ldb_errstring(ldb), ldb_strerror(ret)));
5087                 talloc_free(tmp_ctx);
5088                 return ret;
5089         }
5090
5091         DEBUG(1,("Created new NC for %s\n", ldb_dn_get_linearized(dn)));
5092
5093         talloc_free(tmp_ctx);
5094         return LDB_SUCCESS;
5095 }
5096
5097 /**
5098   build a GUID from a string
5099 */
5100 _PUBLIC_ NTSTATUS NS_GUID_from_string(const char *s, struct GUID *guid)
5101 {
5102         NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
5103         uint32_t time_low;
5104         uint32_t time_mid, time_hi_and_version;
5105         uint32_t clock_seq[2];
5106         uint32_t node[6];
5107         int i;
5108
5109         if (s == NULL) {
5110                 return NT_STATUS_INVALID_PARAMETER;
5111         }
5112
5113         if (11 == sscanf(s, "%08x-%04x%04x-%02x%02x%02x%02x-%02x%02x%02x%02x",
5114                          &time_low, &time_mid, &time_hi_and_version, 
5115                          &clock_seq[0], &clock_seq[1],
5116                          &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) {
5117                 status = NT_STATUS_OK;
5118         }
5119
5120         if (!NT_STATUS_IS_OK(status)) {
5121                 return status;
5122         }
5123
5124         guid->time_low = time_low;
5125         guid->time_mid = time_mid;
5126         guid->time_hi_and_version = time_hi_and_version;
5127         guid->clock_seq[0] = clock_seq[0];
5128         guid->clock_seq[1] = clock_seq[1];
5129         for (i=0;i<6;i++) {
5130                 guid->node[i] = node[i];
5131         }
5132
5133         return NT_STATUS_OK;
5134 }
5135
5136 _PUBLIC_ char *NS_GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid)
5137 {
5138         return talloc_asprintf(mem_ctx, 
5139                                "%08x-%04x%04x-%02x%02x%02x%02x-%02x%02x%02x%02x",
5140                                guid->time_low, guid->time_mid,
5141                                guid->time_hi_and_version,
5142                                guid->clock_seq[0],
5143                                guid->clock_seq[1],
5144                                guid->node[0], guid->node[1],
5145                                guid->node[2], guid->node[3],
5146                                guid->node[4], guid->node[5]);
5147 }
5148
5149 /*
5150  * Return the effective badPwdCount
5151  *
5152  * This requires that the user_msg have (if present):
5153  *  - badPasswordTime
5154  *  - badPwdCount
5155  *
5156  * This also requires that the domain_msg have (if present):
5157  *  - lockOutObservationWindow
5158  */
5159 static int dsdb_effective_badPwdCount(const struct ldb_message *user_msg,
5160                                       int64_t lockOutObservationWindow,
5161                                       NTTIME now)
5162 {
5163         int64_t badPasswordTime;
5164         badPasswordTime = ldb_msg_find_attr_as_int64(user_msg, "badPasswordTime", 0);
5165
5166         if (badPasswordTime - lockOutObservationWindow >= now) {
5167                 return ldb_msg_find_attr_as_int(user_msg, "badPwdCount", 0);
5168         } else {
5169                 return 0;
5170         }
5171 }
5172
5173 /*
5174  * Return the effective badPwdCount
5175  *
5176  * This requires that the user_msg have (if present):
5177  *  - badPasswordTime
5178  *  - badPwdCount
5179  *
5180  */
5181 int samdb_result_effective_badPwdCount(struct ldb_context *sam_ldb,
5182                                        TALLOC_CTX *mem_ctx,
5183                                        struct ldb_dn *domain_dn,
5184                                        const struct ldb_message *user_msg)
5185 {
5186         struct timeval tv_now = timeval_current();
5187         NTTIME now = timeval_to_nttime(&tv_now);
5188         int64_t lockOutObservationWindow = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
5189                                                               "lockOutObservationWindow", NULL);
5190         return dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);
5191 }
5192
5193 /*
5194  * Prepare an update to the badPwdCount and associated attributes.
5195  *
5196  * This requires that the user_msg have (if present):
5197  *  - objectSid
5198  *  - badPasswordTime
5199  *  - badPwdCount
5200  *
5201  * This also requires that the domain_msg have (if present):
5202  *  - pwdProperties
5203  *  - lockoutThreshold
5204  *  - lockOutObservationWindow
5205  */
5206 NTSTATUS dsdb_update_bad_pwd_count(TALLOC_CTX *mem_ctx,
5207                                    struct ldb_context *sam_ctx,
5208                                    struct ldb_message *user_msg,
5209                                    struct ldb_message *domain_msg,
5210                                    struct ldb_message **_mod_msg)
5211 {
5212         int i, ret, badPwdCount;
5213         int64_t lockoutThreshold, lockOutObservationWindow;
5214         struct dom_sid *sid;
5215         struct timeval tv_now = timeval_current();
5216         NTTIME now = timeval_to_nttime(&tv_now);
5217         NTSTATUS status;
5218         uint32_t pwdProperties, rid = 0;
5219         struct ldb_message *mod_msg;
5220
5221         sid = samdb_result_dom_sid(mem_ctx, user_msg, "objectSid");
5222
5223         pwdProperties = ldb_msg_find_attr_as_uint(domain_msg,
5224                                                   "pwdProperties", -1);
5225         if (sid && !(pwdProperties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
5226                 status = dom_sid_split_rid(NULL, sid, NULL, &rid);
5227                 if (!NT_STATUS_IS_OK(status)) {
5228                         /*
5229                          * This can't happen anyway, but always try
5230                          * and update the badPwdCount on failure
5231                          */
5232                         rid = 0;
5233                 }
5234         }
5235         TALLOC_FREE(sid);
5236
5237         /*
5238          * Work out if we are doing password lockout on the domain.
5239          * Also, the built in administrator account is exempt:
5240          * http://msdn.microsoft.com/en-us/library/windows/desktop/aa375371%28v=vs.85%29.aspx
5241          */
5242         lockoutThreshold = ldb_msg_find_attr_as_int(domain_msg,
5243                                                     "lockoutThreshold", 0);
5244         if (lockoutThreshold == 0 || (rid == DOMAIN_RID_ADMINISTRATOR)) {
5245                 DEBUG(5, ("Not updating badPwdCount on %s after wrong password\n",
5246                           ldb_dn_get_linearized(user_msg->dn)));
5247                 return NT_STATUS_OK;
5248         }
5249
5250         mod_msg = ldb_msg_new(mem_ctx);
5251         if (mod_msg == NULL) {
5252                 return NT_STATUS_NO_MEMORY;
5253         }
5254         mod_msg->dn = ldb_dn_copy(mod_msg, user_msg->dn);
5255         if (mod_msg->dn == NULL) {
5256                 TALLOC_FREE(mod_msg);
5257                 return NT_STATUS_NO_MEMORY;
5258         }
5259
5260         lockOutObservationWindow = ldb_msg_find_attr_as_int64(domain_msg,
5261                                                               "lockOutObservationWindow", 0);
5262
5263         badPwdCount = dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);
5264
5265         badPwdCount++;
5266
5267         ret = samdb_msg_add_int(sam_ctx, mod_msg, mod_msg, "badPwdCount", badPwdCount);
5268         if (ret != LDB_SUCCESS) {
5269                 TALLOC_FREE(mod_msg);
5270                 return NT_STATUS_NO_MEMORY;
5271         }
5272         ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "badPasswordTime", now);
5273         if (ret != LDB_SUCCESS) {
5274                 TALLOC_FREE(mod_msg);
5275                 return NT_STATUS_NO_MEMORY;
5276         }
5277
5278         if (badPwdCount >= lockoutThreshold) {
5279                 ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "lockoutTime", now);
5280                 if (ret != LDB_SUCCESS) {
5281                         TALLOC_FREE(mod_msg);
5282                         return NT_STATUS_NO_MEMORY;
5283                 }
5284                 DEBUG(5, ("Locked out user %s after %d wrong passwords\n",
5285                           ldb_dn_get_linearized(user_msg->dn), badPwdCount));
5286         } else {
5287                 DEBUG(5, ("Updated badPwdCount on %s after %d wrong passwords\n",
5288                           ldb_dn_get_linearized(user_msg->dn), badPwdCount));
5289         }
5290
5291         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
5292         for (i=0; i< mod_msg->num_elements; i++) {
5293                 mod_msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5294         }
5295
5296         *_mod_msg = mod_msg;
5297         return NT_STATUS_OK;
5298 }
5299
5300 /**
5301  * Sets defaults for a User object
5302  * List of default attributes set:
5303  *      accountExpires, badPasswordTime, badPwdCount,
5304  *      codePage, countryCode, lastLogoff, lastLogon
5305  *      logonCount, pwdLastSet
5306  */
5307 int dsdb_user_obj_set_defaults(struct ldb_context *ldb,
5308                                struct ldb_message *usr_obj,
5309                                struct ldb_request *req)
5310 {
5311         int i, ret;
5312         const struct attribute_values {
5313                 const char *name;
5314                 const char *value;
5315                 const char *add_value;
5316                 const char *mod_value;
5317                 const char *control;
5318                 unsigned add_flags;
5319                 unsigned mod_flags;
5320         } map[] = {
5321                 {
5322                         .name = "accountExpires",
5323                         .add_value = "9223372036854775807",
5324                         .mod_value = "0",
5325                 },
5326                 {
5327                         .name = "badPasswordTime",
5328                         .value = "0"
5329                 },
5330                 {
5331                         .name = "badPwdCount",
5332                         .value = "0"
5333                 },
5334                 {
5335                         .name = "codePage",
5336                         .value = "0"
5337                 },
5338                 {
5339                         .name = "countryCode",
5340                         .value = "0"
5341                 },
5342                 {
5343                         .name = "lastLogoff",
5344                         .value = "0"
5345                 },
5346                 {
5347                         .name = "lastLogon",
5348                         .value = "0"
5349                 },
5350                 {
5351                         .name = "logonCount",
5352                         .value = "0"
5353                 },
5354                 {
5355                         .name = "logonHours",
5356                         .add_flags = DSDB_FLAG_INTERNAL_FORCE_META_DATA,
5357                 },
5358                 {
5359                         .name = "pwdLastSet",
5360                         .value = "0",
5361                         .control = DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID,
5362                 },
5363                 {
5364                         .name = "adminCount",
5365                         .mod_value = "0",
5366                 },
5367                 {
5368                         .name = "operatorCount",
5369                         .mod_value = "0",
5370                 },
5371         };
5372
5373         for (i = 0; i < ARRAY_SIZE(map); i++) {
5374                 bool added = false;
5375                 const char *value = NULL;
5376                 unsigned flags = 0;
5377
5378                 if (req != NULL && req->operation == LDB_ADD) {
5379                         value = map[i].add_value;
5380                         flags = map[i].add_flags;
5381                 } else {
5382                         value = map[i].mod_value;
5383                         flags = map[i].mod_flags;
5384                 }
5385
5386                 if (value == NULL) {
5387                         value = map[i].value;
5388                 }
5389
5390                 if (value != NULL) {
5391                         flags |= LDB_FLAG_MOD_ADD;
5392                 }
5393
5394                 if (flags == 0) {
5395                         continue;
5396                 }
5397
5398                 ret = samdb_find_or_add_attribute_ex(ldb, usr_obj,
5399                                                      map[i].name,
5400                                                      value, flags,
5401                                                      &added);
5402                 if (ret != LDB_SUCCESS) {
5403                         return ret;
5404                 }
5405
5406                 if (req != NULL && added && map[i].control != NULL) {
5407                         ret = ldb_request_add_control(req,
5408                                                       map[i].control,
5409                                                       false, NULL);
5410                         if (ret != LDB_SUCCESS) {
5411                                 return ret;
5412                         }
5413                 }
5414         }
5415
5416         return LDB_SUCCESS;
5417 }
5418
5419 /**
5420  * Sets 'sAMAccountType on user object based on userAccountControl
5421  * @param ldb Current ldb_context
5422  * @param usr_obj ldb_message representing User object
5423  * @param user_account_control Value for userAccountControl flags
5424  * @param account_type_p Optional pointer to account_type to return
5425  * @return LDB_SUCCESS or LDB_ERR* code on failure
5426  */
5427 int dsdb_user_obj_set_account_type(struct ldb_context *ldb, struct ldb_message *usr_obj,
5428                                    uint32_t user_account_control, uint32_t *account_type_p)
5429 {
5430         int ret;
5431         uint32_t account_type;
5432         struct ldb_message_element *el;
5433
5434         account_type = ds_uf2atype(user_account_control);
5435         if (account_type == 0) {
5436                 ldb_set_errstring(ldb, "dsdb: Unrecognized account type!");
5437                 return LDB_ERR_UNWILLING_TO_PERFORM;
5438         }
5439         ret = samdb_msg_add_uint(ldb, usr_obj, usr_obj,
5440                                  "sAMAccountType",
5441                                  account_type);
5442         if (ret != LDB_SUCCESS) {
5443                 return ret;
5444         }
5445         el = ldb_msg_find_element(usr_obj, "sAMAccountType");
5446         el->flags = LDB_FLAG_MOD_REPLACE;
5447
5448         if (account_type_p) {
5449                 *account_type_p = account_type;
5450         }
5451
5452         return LDB_SUCCESS;
5453 }
5454
5455 /**
5456  * Determine and set primaryGroupID based on userAccountControl value
5457  * @param ldb Current ldb_context
5458  * @param usr_obj ldb_message representing User object
5459  * @param user_account_control Value for userAccountControl flags
5460  * @param group_rid_p Optional pointer to group RID to return
5461  * @return LDB_SUCCESS or LDB_ERR* code on failure
5462  */
5463 int dsdb_user_obj_set_primary_group_id(struct ldb_context *ldb, struct ldb_message *usr_obj,
5464                                        uint32_t user_account_control, uint32_t *group_rid_p)
5465 {
5466         int ret;
5467         uint32_t rid;
5468         struct ldb_message_element *el;
5469
5470         rid = ds_uf2prim_group_rid(user_account_control);
5471
5472         ret = samdb_msg_add_uint(ldb, usr_obj, usr_obj,
5473                                  "primaryGroupID", rid);
5474         if (ret != LDB_SUCCESS) {
5475                 return ret;
5476         }
5477         el = ldb_msg_find_element(usr_obj, "primaryGroupID");
5478         el->flags = LDB_FLAG_MOD_REPLACE;
5479
5480         if (group_rid_p) {
5481                 *group_rid_p = rid;
5482         }
5483
5484         return LDB_SUCCESS;
5485 }