s4:samdb_set_password/samdb_set_password_sid - Better comments and cosmetics
[sfrench/samba-autobuild/.git] / source4 / dsdb / common / util.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba utility functions
4
5    Copyright (C) Andrew Tridgell 2004
6    Copyright (C) Volker Lendecke 2004
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "events/events.h"
26 #include "ldb.h"
27 #include "ldb_errors.h"
28 #include "../lib/util/util_ldb.h"
29 #include "../lib/crypto/crypto.h"
30 #include "dsdb/samdb/samdb.h"
31 #include "libcli/security/security.h"
32 #include "librpc/gen_ndr/ndr_security.h"
33 #include "librpc/gen_ndr/ndr_misc.h"
34 #include "../libds/common/flags.h"
35 #include "dsdb/common/proto.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "param/param.h"
38 #include "libcli/auth/libcli_auth.h"
39 #include "librpc/gen_ndr/ndr_drsblobs.h"
40
41 /*
42   search the sam for the specified attributes in a specific domain, filter on
43   objectSid being in domain_sid.
44 */
45 int samdb_search_domain(struct ldb_context *sam_ldb,
46                         TALLOC_CTX *mem_ctx, 
47                         struct ldb_dn *basedn,
48                         struct ldb_message ***res,
49                         const char * const *attrs,
50                         const struct dom_sid *domain_sid,
51                         const char *format, ...)  _PRINTF_ATTRIBUTE(7,8)
52 {
53         va_list ap;
54         int i, count;
55
56         va_start(ap, format);
57         count = gendb_search_v(sam_ldb, mem_ctx, basedn,
58                                res, attrs, format, ap);
59         va_end(ap);
60
61         i=0;
62
63         while (i<count) {
64                 struct dom_sid *entry_sid;
65
66                 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
67
68                 if ((entry_sid == NULL) ||
69                     (!dom_sid_in_domain(domain_sid, entry_sid))) {
70                         /* Delete that entry from the result set */
71                         (*res)[i] = (*res)[count-1];
72                         count -= 1;
73                         talloc_free(entry_sid);
74                         continue;
75                 }
76                 talloc_free(entry_sid);
77                 i += 1;
78         }
79
80         return count;
81 }
82
83 /*
84   search the sam for a single string attribute in exactly 1 record
85 */
86 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
87                                   TALLOC_CTX *mem_ctx,
88                                   struct ldb_dn *basedn,
89                                   const char *attr_name,
90                                   const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
91 {
92         int count;
93         const char *attrs[2] = { NULL, NULL };
94         struct ldb_message **res = NULL;
95
96         attrs[0] = attr_name;
97
98         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
99         if (count > 1) {                
100                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
101                          attr_name, format, count));
102         }
103         if (count != 1) {
104                 talloc_free(res);
105                 return NULL;
106         }
107
108         return samdb_result_string(res[0], attr_name, NULL);
109 }
110
111 /*
112   search the sam for a single string attribute in exactly 1 record
113 */
114 const char *samdb_search_string(struct ldb_context *sam_ldb,
115                                 TALLOC_CTX *mem_ctx,
116                                 struct ldb_dn *basedn,
117                                 const char *attr_name,
118                                 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
119 {
120         va_list ap;
121         const char *str;
122
123         va_start(ap, format);
124         str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
125         va_end(ap);
126
127         return str;
128 }
129
130 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
131                                TALLOC_CTX *mem_ctx,
132                                struct ldb_dn *basedn,
133                                const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
134 {
135         va_list ap;
136         struct ldb_dn *ret;
137         struct ldb_message **res = NULL;
138         int count;
139
140         va_start(ap, format);
141         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
142         va_end(ap);
143
144         if (count != 1) return NULL;
145
146         ret = talloc_steal(mem_ctx, res[0]->dn);
147         talloc_free(res);
148
149         return ret;
150 }
151
152 /*
153   search the sam for a dom_sid attribute in exactly 1 record
154 */
155 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
156                                      TALLOC_CTX *mem_ctx,
157                                      struct ldb_dn *basedn,
158                                      const char *attr_name,
159                                      const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
160 {
161         va_list ap;
162         int count;
163         struct ldb_message **res;
164         const char *attrs[2] = { NULL, NULL };
165         struct dom_sid *sid;
166
167         attrs[0] = attr_name;
168
169         va_start(ap, format);
170         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
171         va_end(ap);
172         if (count > 1) {                
173                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
174                          attr_name, format, count));
175         }
176         if (count != 1) {
177                 talloc_free(res);
178                 return NULL;
179         }
180         sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
181         talloc_free(res);
182         return sid;     
183 }
184
185 /*
186   return the count of the number of records in the sam matching the query
187 */
188 int samdb_search_count(struct ldb_context *sam_ldb,
189                        TALLOC_CTX *mem_ctx,
190                        struct ldb_dn *basedn,
191                        const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
192 {
193         va_list ap;
194         struct ldb_message **res;
195         const char * const attrs[] = { NULL };
196         int ret;
197
198         va_start(ap, format);
199         ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
200         va_end(ap);
201
202         return ret;
203 }
204
205
206 /*
207   search the sam for a single integer attribute in exactly 1 record
208 */
209 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
210                          TALLOC_CTX *mem_ctx,
211                          uint_t default_value,
212                          struct ldb_dn *basedn,
213                          const char *attr_name,
214                          const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
215 {
216         va_list ap;
217         int count;
218         struct ldb_message **res;
219         const char *attrs[2] = { NULL, NULL };
220
221         attrs[0] = attr_name;
222
223         va_start(ap, format);
224         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
225         va_end(ap);
226
227         if (count != 1) {
228                 return default_value;
229         }
230
231         return samdb_result_uint(res[0], attr_name, default_value);
232 }
233
234 /*
235   search the sam for a single signed 64 bit integer attribute in exactly 1 record
236 */
237 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
238                            TALLOC_CTX *mem_ctx,
239                            int64_t default_value,
240                            struct ldb_dn *basedn,
241                            const char *attr_name,
242                            const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
243 {
244         va_list ap;
245         int count;
246         struct ldb_message **res;
247         const char *attrs[2] = { NULL, NULL };
248
249         attrs[0] = attr_name;
250
251         va_start(ap, format);
252         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
253         va_end(ap);
254
255         if (count != 1) {
256                 return default_value;
257         }
258
259         return samdb_result_int64(res[0], attr_name, default_value);
260 }
261
262 /*
263   search the sam for multipe records each giving a single string attribute
264   return the number of matches, or -1 on error
265 */
266 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
267                                  TALLOC_CTX *mem_ctx,
268                                  struct ldb_dn *basedn,
269                                  const char ***strs,
270                                  const char *attr_name,
271                                  const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
272 {
273         va_list ap;
274         int count, i;
275         const char *attrs[2] = { NULL, NULL };
276         struct ldb_message **res = NULL;
277
278         attrs[0] = attr_name;
279
280         va_start(ap, format);
281         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
282         va_end(ap);
283
284         if (count <= 0) {
285                 return count;
286         }
287
288         /* make sure its single valued */
289         for (i=0;i<count;i++) {
290                 if (res[i]->num_elements != 1) {
291                         DEBUG(1,("samdb: search for %s %s not single valued\n", 
292                                  attr_name, format));
293                         talloc_free(res);
294                         return -1;
295                 }
296         }
297
298         *strs = talloc_array(mem_ctx, const char *, count+1);
299         if (! *strs) {
300                 talloc_free(res);
301                 return -1;
302         }
303
304         for (i=0;i<count;i++) {
305                 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
306         }
307         (*strs)[count] = NULL;
308
309         return count;
310 }
311
312 /*
313   pull a uint from a result set. 
314 */
315 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
316 {
317         return ldb_msg_find_attr_as_uint(msg, attr, default_value);
318 }
319
320 /*
321   pull a (signed) int64 from a result set. 
322 */
323 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
324 {
325         return ldb_msg_find_attr_as_int64(msg, attr, default_value);
326 }
327
328 /*
329   pull a string from a result set. 
330 */
331 const char *samdb_result_string(const struct ldb_message *msg, const char *attr, 
332                                 const char *default_value)
333 {
334         return ldb_msg_find_attr_as_string(msg, attr, default_value);
335 }
336
337 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
338                                const char *attr, struct ldb_dn *default_value)
339 {
340         struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
341         if (!ret_dn) {
342                 return default_value;
343         }
344         return ret_dn;
345 }
346
347 /*
348   pull a rid from a objectSid in a result set. 
349 */
350 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
351                                    const char *attr, uint32_t default_value)
352 {
353         struct dom_sid *sid;
354         uint32_t rid;
355
356         sid = samdb_result_dom_sid(mem_ctx, msg, attr);
357         if (sid == NULL) {
358                 return default_value;
359         }
360         rid = sid->sub_auths[sid->num_auths-1];
361         talloc_free(sid);
362         return rid;
363 }
364
365 /*
366   pull a dom_sid structure from a objectSid in a result set. 
367 */
368 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
369                                      const char *attr)
370 {
371         const struct ldb_val *v;
372         struct dom_sid *sid;
373         enum ndr_err_code ndr_err;
374         v = ldb_msg_find_ldb_val(msg, attr);
375         if (v == NULL) {
376                 return NULL;
377         }
378         sid = talloc(mem_ctx, struct dom_sid);
379         if (sid == NULL) {
380                 return NULL;
381         }
382         ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
383                                        (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
384         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
385                 talloc_free(sid);
386                 return NULL;
387         }
388         return sid;
389 }
390
391 /*
392   pull a guid structure from a objectGUID in a result set. 
393 */
394 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
395 {
396         const struct ldb_val *v;
397         enum ndr_err_code ndr_err;
398         struct GUID guid;
399         TALLOC_CTX *mem_ctx;
400
401         ZERO_STRUCT(guid);
402
403         v = ldb_msg_find_ldb_val(msg, attr);
404         if (!v) return guid;
405
406         mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
407         if (!mem_ctx) return guid;
408         ndr_err = ndr_pull_struct_blob(v, mem_ctx, NULL, &guid,
409                                        (ndr_pull_flags_fn_t)ndr_pull_GUID);
410         talloc_free(mem_ctx);
411         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
412                 return guid;
413         }
414
415         return guid;
416 }
417
418 /*
419   pull a sid prefix from a objectSid in a result set. 
420   this is used to find the domain sid for a user
421 */
422 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
423                                         const char *attr)
424 {
425         struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
426         if (!sid || sid->num_auths < 1) return NULL;
427         sid->num_auths--;
428         return sid;
429 }
430
431 /*
432   pull a NTTIME in a result set. 
433 */
434 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
435 {
436         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
437 }
438
439 /*
440  * Windows stores 0 for lastLogoff.
441  * But when a MS DC return the lastLogoff (as Logoff Time)
442  * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
443  * cause windows 2008 and newer version to fail for SMB requests
444  */
445 NTTIME samdb_result_last_logoff(struct ldb_message *msg)
446 {
447         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
448
449         if (ret == 0)
450                 ret = 0x7FFFFFFFFFFFFFFFULL;
451
452         return ret;
453 }
454
455 /*
456  * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
457  * indicate an account doesn't expire.
458  *
459  * When Windows initially creates an account, it sets
460  * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF).  However,
461  * when changing from an account having a specific expiration date to
462  * that account never expiring, it sets accountExpires = 0.
463  *
464  * Consolidate that logic here to allow clearer logic for account expiry in
465  * the rest of the code.
466  */
467 NTTIME samdb_result_account_expires(struct ldb_message *msg)
468 {
469         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
470                                                  0);
471
472         if (ret == 0)
473                 ret = 0x7FFFFFFFFFFFFFFFULL;
474
475         return ret;
476 }
477
478 /*
479   pull a uint64_t from a result set. 
480 */
481 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
482 {
483         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
484 }
485
486
487 /*
488   construct the allow_password_change field from the PwdLastSet attribute and the 
489   domain password settings
490 */
491 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb, 
492                                           TALLOC_CTX *mem_ctx, 
493                                           struct ldb_dn *domain_dn, 
494                                           struct ldb_message *msg, 
495                                           const char *attr)
496 {
497         uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
498         int64_t minPwdAge;
499
500         if (attr_time == 0) {
501                 return 0;
502         }
503
504         minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
505
506         /* yes, this is a -= not a += as minPwdAge is stored as the negative
507            of the number of 100-nano-seconds */
508         attr_time -= minPwdAge;
509
510         return attr_time;
511 }
512
513 /*
514   construct the force_password_change field from the PwdLastSet
515   attribute, the userAccountControl and the domain password settings
516 */
517 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb, 
518                                           TALLOC_CTX *mem_ctx, 
519                                           struct ldb_dn *domain_dn, 
520                                           struct ldb_message *msg)
521 {
522         uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
523         uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
524         int64_t maxPwdAge;
525
526         /* Machine accounts don't expire, and there is a flag for 'no expiry' */
527         if (!(userAccountControl & UF_NORMAL_ACCOUNT)
528             || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
529                 return 0x7FFFFFFFFFFFFFFFULL;
530         }
531
532         if (attr_time == 0) {
533                 return 0;
534         }
535
536         maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
537         if (maxPwdAge == 0) {
538                 return 0x7FFFFFFFFFFFFFFFULL;
539         } else {
540                 attr_time -= maxPwdAge;
541         }
542
543         return attr_time;
544 }
545
546 /*
547   pull a samr_Password structutre from a result set. 
548 */
549 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
550 {
551         struct samr_Password *hash = NULL;
552         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
553         if (val && (val->length >= sizeof(hash->hash))) {
554                 hash = talloc(mem_ctx, struct samr_Password);
555                 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
556         }
557         return hash;
558 }
559
560 /*
561   pull an array of samr_Password structutres from a result set. 
562 */
563 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
564                            const char *attr, struct samr_Password **hashes)
565 {
566         uint_t count = 0;
567         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
568         int i;
569
570         *hashes = NULL;
571         if (!val) {
572                 return 0;
573         }
574         count = val->length / 16;
575         if (count == 0) {
576                 return 0;
577         }
578
579         *hashes = talloc_array(mem_ctx, struct samr_Password, count);
580         if (! *hashes) {
581                 return 0;
582         }
583
584         for (i=0;i<count;i++) {
585                 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
586         }
587
588         return count;
589 }
590
591 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg, 
592                                 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd) 
593 {
594         struct samr_Password *lmPwdHash, *ntPwdHash;
595         if (nt_pwd) {
596                 int num_nt;
597                 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
598                 if (num_nt == 0) {
599                         *nt_pwd = NULL;
600                 } else if (num_nt > 1) {
601                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
602                 } else {
603                         *nt_pwd = &ntPwdHash[0];
604                 }
605         }
606         if (lm_pwd) {
607                 /* Ensure that if we have turned off LM
608                  * authentication, that we never use the LM hash, even
609                  * if we store it */
610                 if (lp_lanman_auth(lp_ctx)) {
611                         int num_lm;
612                         num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
613                         if (num_lm == 0) {
614                                 *lm_pwd = NULL;
615                         } else if (num_lm > 1) {
616                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
617                         } else {
618                                 *lm_pwd = &lmPwdHash[0];
619                         }
620                 } else {
621                         *lm_pwd = NULL;
622                 }
623         }
624         return NT_STATUS_OK;
625 }
626
627 /*
628   pull a samr_LogonHours structutre from a result set. 
629 */
630 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
631 {
632         struct samr_LogonHours hours;
633         const int units_per_week = 168;
634         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
635         ZERO_STRUCT(hours);
636         hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
637         if (!hours.bits) {
638                 return hours;
639         }
640         hours.units_per_week = units_per_week;
641         memset(hours.bits, 0xFF, units_per_week);
642         if (val) {
643                 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
644         }
645         return hours;
646 }
647
648 /*
649   pull a set of account_flags from a result set. 
650
651   This requires that the attributes: 
652    pwdLastSet
653    userAccountControl
654   be included in 'msg'
655 */
656 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
657                                  struct ldb_message *msg, struct ldb_dn *domain_dn)
658 {
659         uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
660         uint32_t acct_flags = ds_uf2acb(userAccountControl);
661         NTTIME must_change_time;
662         NTTIME now;
663
664         must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx, 
665                                                               domain_dn, msg);
666
667         /* Test account expire time */
668         unix_to_nt_time(&now, time(NULL));
669         /* check for expired password */
670         if (must_change_time < now) {
671                 acct_flags |= ACB_PW_EXPIRED;
672         }
673         return acct_flags;
674 }
675
676 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
677                                                 struct ldb_message *msg,
678                                                 const char *attr)
679 {
680         struct lsa_BinaryString s;
681         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
682
683         ZERO_STRUCT(s);
684
685         if (!val) {
686                 return s;
687         }
688
689         s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
690         if (!s.array) {
691                 return s;
692         }
693         s.length = s.size = val->length/2;
694         memcpy(s.array, val->data, val->length);
695
696         return s;
697 }
698
699 /* Find an attribute, with a particular value */
700
701 /* The current callers of this function expect a very specific
702  * behaviour: In particular, objectClass subclass equivilance is not
703  * wanted.  This means that we should not lookup the schema for the
704  * comparison function */
705 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb, 
706                                                  const struct ldb_message *msg, 
707                                                  const char *name, const char *value)
708 {
709         int i;
710         struct ldb_message_element *el = ldb_msg_find_element(msg, name);
711
712         if (!el) {
713                 return NULL;
714         }
715
716         for (i=0;i<el->num_values;i++) {
717                 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
718                         return el;
719                 }
720         }
721
722         return NULL;
723 }
724
725 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
726 {
727         if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
728                 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
729         }
730         return LDB_SUCCESS;
731 }
732
733 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
734 {
735         struct ldb_message_element *el;
736
737         el = ldb_msg_find_element(msg, name);
738         if (el) {
739                 return LDB_SUCCESS;
740         }
741
742         return samdb_msg_add_string(ldb, msg, msg, name, set_value);
743 }
744
745
746
747 /*
748   add a string element to a message
749 */
750 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
751                          const char *attr_name, const char *str)
752 {
753         char *s = talloc_strdup(mem_ctx, str);
754         char *a = talloc_strdup(mem_ctx, attr_name);
755         if (s == NULL || a == NULL) {
756                 return LDB_ERR_OPERATIONS_ERROR;
757         }
758         return ldb_msg_add_string(msg, a, s);
759 }
760
761 /*
762   add a dom_sid element to a message
763 */
764 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
765                          const char *attr_name, struct dom_sid *sid)
766 {
767         struct ldb_val v;
768         enum ndr_err_code ndr_err;
769
770         ndr_err = ndr_push_struct_blob(&v, mem_ctx, 
771                                        lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
772                                        sid,
773                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
774         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
775                 return -1;
776         }
777         return ldb_msg_add_value(msg, attr_name, &v, NULL);
778 }
779
780
781 /*
782   add a delete element operation to a message
783 */
784 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
785                          const char *attr_name)
786 {
787         /* we use an empty replace rather than a delete, as it allows for 
788            samdb_replace() to be used everywhere */
789         return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
790 }
791
792 /*
793   add a add attribute value to a message
794 */
795 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
796                          const char *attr_name, const char *value)
797 {
798         struct ldb_message_element *el;
799         char *a, *v;
800         int ret;
801         a = talloc_strdup(mem_ctx, attr_name);
802         if (a == NULL)
803                 return -1;
804         v = talloc_strdup(mem_ctx, value);
805         if (v == NULL)
806                 return -1;
807         ret = ldb_msg_add_string(msg, a, v);
808         if (ret != 0)
809                 return ret;
810         el = ldb_msg_find_element(msg, a);
811         if (el == NULL)
812                 return -1;
813         el->flags = LDB_FLAG_MOD_ADD;
814         return 0;
815 }
816
817 /*
818   add a delete attribute value to a message
819 */
820 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
821                          const char *attr_name, const char *value)
822 {
823         struct ldb_message_element *el;
824         char *a, *v;
825         int ret;
826         a = talloc_strdup(mem_ctx, attr_name);
827         if (a == NULL)
828                 return -1;
829         v = talloc_strdup(mem_ctx, value);
830         if (v == NULL)
831                 return -1;
832         ret = ldb_msg_add_string(msg, a, v);
833         if (ret != 0)
834                 return ret;
835         el = ldb_msg_find_element(msg, a);
836         if (el == NULL)
837                 return -1;
838         el->flags = LDB_FLAG_MOD_DELETE;
839         return 0;
840 }
841
842 /*
843   add a int element to a message
844 */
845 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
846                        const char *attr_name, int v)
847 {
848         const char *s = talloc_asprintf(mem_ctx, "%d", v);
849         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
850 }
851
852 /*
853   add a uint_t element to a message
854 */
855 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
856                        const char *attr_name, uint_t v)
857 {
858         const char *s = talloc_asprintf(mem_ctx, "%u", v);
859         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
860 }
861
862 /*
863   add a (signed) int64_t element to a message
864 */
865 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
866                         const char *attr_name, int64_t v)
867 {
868         const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
869         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
870 }
871
872 /*
873   add a uint64_t element to a message
874 */
875 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
876                         const char *attr_name, uint64_t v)
877 {
878         const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
879         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
880 }
881
882 /*
883   add a samr_Password element to a message
884 */
885 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
886                        const char *attr_name, struct samr_Password *hash)
887 {
888         struct ldb_val val;
889         val.data = talloc_memdup(mem_ctx, hash->hash, 16);
890         if (!val.data) {
891                 return -1;
892         }
893         val.length = 16;
894         return ldb_msg_add_value(msg, attr_name, &val, NULL);
895 }
896
897 /*
898   add a samr_Password array to a message
899 */
900 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
901                          const char *attr_name, struct samr_Password *hashes, uint_t count)
902 {
903         struct ldb_val val;
904         int i;
905         val.data = talloc_array_size(mem_ctx, 16, count);
906         val.length = count*16;
907         if (!val.data) {
908                 return -1;
909         }
910         for (i=0;i<count;i++) {
911                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
912         }
913         return ldb_msg_add_value(msg, attr_name, &val, NULL);
914 }
915
916 /*
917   add a acct_flags element to a message
918 */
919 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
920                              const char *attr_name, uint32_t v)
921 {
922         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
923 }
924
925 /*
926   add a logon_hours element to a message
927 */
928 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
929                               const char *attr_name, struct samr_LogonHours *hours)
930 {
931         struct ldb_val val;
932         val.length = hours->units_per_week / 8;
933         val.data = hours->bits;
934         return ldb_msg_add_value(msg, attr_name, &val, NULL);
935 }
936
937 /*
938   add a parameters element to a message
939 */
940 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
941                              const char *attr_name, struct lsa_BinaryString *parameters)
942 {
943         struct ldb_val val;
944         val.length = parameters->length * 2;
945         val.data = (uint8_t *)parameters->array;
946         return ldb_msg_add_value(msg, attr_name, &val, NULL);
947 }
948 /*
949   add a general value element to a message
950 */
951 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
952                               const char *attr_name, const struct ldb_val *val)
953 {
954         return ldb_msg_add_value(msg, attr_name, val, NULL);
955 }
956
957 /*
958   sets a general value element to a message
959 */
960 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
961                         const char *attr_name, const struct ldb_val *val)
962 {
963         struct ldb_message_element *el;
964
965         el = ldb_msg_find_element(msg, attr_name);
966         if (el) {
967                 el->num_values = 0;
968         }
969         return ldb_msg_add_value(msg, attr_name, val, NULL);
970 }
971
972 /*
973   set a string element in a message
974 */
975 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
976                          const char *attr_name, const char *str)
977 {
978         struct ldb_message_element *el;
979
980         el = ldb_msg_find_element(msg, attr_name);
981         if (el) {
982                 el->num_values = 0;
983         }
984         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
985 }
986
987 /*
988   replace elements in a record
989 */
990 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
991 {
992         int i;
993
994         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
995         for (i=0;i<msg->num_elements;i++) {
996                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
997         }
998
999         /* modify the samdb record */
1000         return ldb_modify(sam_ldb, msg);
1001 }
1002
1003 /*
1004   return a default security descriptor
1005 */
1006 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1007 {
1008         struct security_descriptor *sd;
1009
1010         sd = security_descriptor_initialise(mem_ctx);
1011
1012         return sd;
1013 }
1014
1015 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx) 
1016 {
1017         return ldb_get_default_basedn(sam_ctx);
1018 }
1019
1020 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx) 
1021 {
1022         return ldb_get_config_basedn(sam_ctx);
1023 }
1024
1025 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx) 
1026 {
1027         return ldb_get_schema_basedn(sam_ctx);
1028 }
1029
1030 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx) 
1031 {
1032         return ldb_get_root_basedn(sam_ctx);
1033 }
1034
1035 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1036 {
1037         struct ldb_dn *new_dn;
1038
1039         new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1040         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1041                 talloc_free(new_dn);
1042                 return NULL;
1043         }
1044         return new_dn;
1045 }
1046
1047 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1048 {
1049         struct ldb_dn *new_dn;
1050
1051         new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1052         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1053                 talloc_free(new_dn);
1054                 return NULL;
1055         }
1056         return new_dn;
1057 }
1058
1059 /*
1060   work out the domain sid for the current open ldb
1061 */
1062 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1063 {
1064         TALLOC_CTX *tmp_ctx;
1065         const struct dom_sid *domain_sid;
1066         const char *attrs[] = {
1067                 "objectSid",
1068                 NULL
1069         };
1070         struct ldb_result *res;
1071         int ret;
1072
1073         /* see if we have a cached copy */
1074         domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1075         if (domain_sid) {
1076                 return domain_sid;
1077         }
1078
1079         tmp_ctx = talloc_new(ldb);
1080         if (tmp_ctx == NULL) {
1081                 goto failed;
1082         }
1083
1084         ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1085
1086         if (ret != LDB_SUCCESS) {
1087                 goto failed;
1088         }
1089
1090         if (res->count != 1) {
1091                 goto failed;
1092         }
1093
1094         domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1095         if (domain_sid == NULL) {
1096                 goto failed;
1097         }
1098
1099         /* cache the domain_sid in the ldb */
1100         if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1101                 goto failed;
1102         }
1103
1104         talloc_steal(ldb, domain_sid);
1105         talloc_free(tmp_ctx);
1106
1107         return domain_sid;
1108
1109 failed:
1110         DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1111         talloc_free(tmp_ctx);
1112         return NULL;
1113 }
1114
1115 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1116 {
1117         TALLOC_CTX *tmp_ctx;
1118         struct dom_sid *dom_sid_new;
1119         struct dom_sid *dom_sid_old;
1120
1121         /* see if we have a cached copy */
1122         dom_sid_old = talloc_get_type(ldb_get_opaque(ldb, 
1123                                                      "cache.domain_sid"), struct dom_sid);
1124
1125         tmp_ctx = talloc_new(ldb);
1126         if (tmp_ctx == NULL) {
1127                 goto failed;
1128         }
1129
1130         dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1131         if (!dom_sid_new) {
1132                 goto failed;
1133         }
1134
1135         /* cache the domain_sid in the ldb */
1136         if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1137                 goto failed;
1138         }
1139
1140         talloc_steal(ldb, dom_sid_new);
1141         talloc_free(tmp_ctx);
1142         talloc_free(dom_sid_old);
1143
1144         return true;
1145
1146 failed:
1147         DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1148         talloc_free(tmp_ctx);
1149         return false;
1150 }
1151
1152 /* Obtain the short name of the flexible single master operator
1153  * (FSMO), such as the PDC Emulator */
1154 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
1155                              const char *attr)
1156 {
1157         /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1158         struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1159         const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1160         const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1161
1162         if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1163                 /* Ensure this matches the format.  This gives us a
1164                  * bit more confidence that a 'cn' value will be a
1165                  * ascii string */
1166                 return NULL;
1167         }
1168         if (val) {
1169                 return (char *)val->data;
1170         }
1171         return NULL;
1172 }
1173
1174 /*
1175   work out the ntds settings dn for the current open ldb
1176 */
1177 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1178 {
1179         TALLOC_CTX *tmp_ctx;
1180         const char *root_attrs[] = { "dsServiceName", NULL };
1181         int ret;
1182         struct ldb_result *root_res;
1183         struct ldb_dn *settings_dn;
1184
1185         /* see if we have a cached copy */
1186         settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1187         if (settings_dn) {
1188                 return settings_dn;
1189         }
1190
1191         tmp_ctx = talloc_new(ldb);
1192         if (tmp_ctx == NULL) {
1193                 goto failed;
1194         }
1195
1196         ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1197         if (ret) {
1198                 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n", 
1199                          ldb_errstring(ldb)));
1200                 goto failed;
1201         }
1202
1203         if (root_res->count != 1) {
1204                 goto failed;
1205         }
1206
1207         settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1208
1209         /* cache the domain_sid in the ldb */
1210         if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1211                 goto failed;
1212         }
1213
1214         talloc_steal(ldb, settings_dn);
1215         talloc_free(tmp_ctx);
1216
1217         return settings_dn;
1218
1219 failed:
1220         DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1221         talloc_free(tmp_ctx);
1222         return NULL;
1223 }
1224
1225 /*
1226   work out the ntds settings invocationId for the current open ldb
1227 */
1228 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1229 {
1230         TALLOC_CTX *tmp_ctx;
1231         const char *attrs[] = { "invocationId", NULL };
1232         int ret;
1233         struct ldb_result *res;
1234         struct GUID *invocation_id;
1235
1236         /* see if we have a cached copy */
1237         invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1238         if (invocation_id) {
1239                 return invocation_id;
1240         }
1241
1242         tmp_ctx = talloc_new(ldb);
1243         if (tmp_ctx == NULL) {
1244                 goto failed;
1245         }
1246
1247         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1248         if (ret) {
1249                 goto failed;
1250         }
1251
1252         if (res->count != 1) {
1253                 goto failed;
1254         }
1255
1256         invocation_id = talloc(tmp_ctx, struct GUID);
1257         if (!invocation_id) {
1258                 goto failed;
1259         }
1260
1261         *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1262
1263         /* cache the domain_sid in the ldb */
1264         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1265                 goto failed;
1266         }
1267
1268         talloc_steal(ldb, invocation_id);
1269         talloc_free(tmp_ctx);
1270
1271         return invocation_id;
1272
1273 failed:
1274         DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1275         talloc_free(tmp_ctx);
1276         return NULL;
1277 }
1278
1279 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1280 {
1281         TALLOC_CTX *tmp_ctx;
1282         struct GUID *invocation_id_new;
1283         struct GUID *invocation_id_old;
1284
1285         /* see if we have a cached copy */
1286         invocation_id_old = (struct GUID *)ldb_get_opaque(ldb, 
1287                                                          "cache.invocation_id");
1288
1289         tmp_ctx = talloc_new(ldb);
1290         if (tmp_ctx == NULL) {
1291                 goto failed;
1292         }
1293
1294         invocation_id_new = talloc(tmp_ctx, struct GUID);
1295         if (!invocation_id_new) {
1296                 goto failed;
1297         }
1298
1299         *invocation_id_new = *invocation_id_in;
1300
1301         /* cache the domain_sid in the ldb */
1302         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1303                 goto failed;
1304         }
1305
1306         talloc_steal(ldb, invocation_id_new);
1307         talloc_free(tmp_ctx);
1308         talloc_free(invocation_id_old);
1309
1310         return true;
1311
1312 failed:
1313         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1314         talloc_free(tmp_ctx);
1315         return false;
1316 }
1317
1318 /*
1319   work out the ntds settings objectGUID for the current open ldb
1320 */
1321 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1322 {
1323         TALLOC_CTX *tmp_ctx;
1324         const char *attrs[] = { "objectGUID", NULL };
1325         int ret;
1326         struct ldb_result *res;
1327         struct GUID *ntds_guid;
1328
1329         /* see if we have a cached copy */
1330         ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1331         if (ntds_guid) {
1332                 return ntds_guid;
1333         }
1334
1335         tmp_ctx = talloc_new(ldb);
1336         if (tmp_ctx == NULL) {
1337                 goto failed;
1338         }
1339
1340         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1341         if (ret) {
1342                 goto failed;
1343         }
1344
1345         if (res->count != 1) {
1346                 goto failed;
1347         }
1348
1349         ntds_guid = talloc(tmp_ctx, struct GUID);
1350         if (!ntds_guid) {
1351                 goto failed;
1352         }
1353
1354         *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1355
1356         /* cache the domain_sid in the ldb */
1357         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1358                 goto failed;
1359         }
1360
1361         talloc_steal(ldb, ntds_guid);
1362         talloc_free(tmp_ctx);
1363
1364         return ntds_guid;
1365
1366 failed:
1367         DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1368         talloc_free(tmp_ctx);
1369         return NULL;
1370 }
1371
1372 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1373 {
1374         TALLOC_CTX *tmp_ctx;
1375         struct GUID *ntds_guid_new;
1376         struct GUID *ntds_guid_old;
1377
1378         /* see if we have a cached copy */
1379         ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1380
1381         tmp_ctx = talloc_new(ldb);
1382         if (tmp_ctx == NULL) {
1383                 goto failed;
1384         }
1385
1386         ntds_guid_new = talloc(tmp_ctx, struct GUID);
1387         if (!ntds_guid_new) {
1388                 goto failed;
1389         }
1390
1391         *ntds_guid_new = *ntds_guid_in;
1392
1393         /* cache the domain_sid in the ldb */
1394         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1395                 goto failed;
1396         }
1397
1398         talloc_steal(ldb, ntds_guid_new);
1399         talloc_free(tmp_ctx);
1400         talloc_free(ntds_guid_old);
1401
1402         return true;
1403
1404 failed:
1405         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1406         talloc_free(tmp_ctx);
1407         return false;
1408 }
1409
1410 /*
1411   work out the server dn for the current open ldb
1412 */
1413 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1414 {
1415         return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1416 }
1417
1418 /*
1419   work out the server dn for the current open ldb
1420 */
1421 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1422 {
1423         struct ldb_dn *server_dn;
1424         struct ldb_dn *server_site_dn;
1425
1426         server_dn = samdb_server_dn(ldb, mem_ctx);
1427         if (!server_dn) return NULL;
1428
1429         server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1430
1431         talloc_free(server_dn);
1432         return server_site_dn;
1433 }
1434
1435 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1436 {
1437         const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb, mem_ctx));
1438
1439         if (val != NULL)
1440                 return (const char *) val->data;
1441         else
1442                 return NULL;
1443 }
1444
1445 /*
1446   work out if we are the PDC for the domain of the current open ldb
1447 */
1448 bool samdb_is_pdc(struct ldb_context *ldb)
1449 {
1450         const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1451         int ret;
1452         struct ldb_result *dom_res;
1453         TALLOC_CTX *tmp_ctx;
1454         bool is_pdc;
1455         struct ldb_dn *pdc;
1456
1457         tmp_ctx = talloc_new(ldb);
1458         if (tmp_ctx == NULL) {
1459                 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1460                 return false;
1461         }
1462
1463         ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1464         if (ret) {
1465                 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n", 
1466                          ldb_dn_get_linearized(ldb_get_default_basedn(ldb)), 
1467                          ldb_errstring(ldb)));
1468                 goto failed;
1469         }
1470         if (dom_res->count != 1) {
1471                 goto failed;
1472         }
1473
1474         pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1475
1476         if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1477                 is_pdc = true;
1478         } else {
1479                 is_pdc = false;
1480         }
1481
1482         talloc_free(tmp_ctx);
1483
1484         return is_pdc;
1485
1486 failed:
1487         DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1488         talloc_free(tmp_ctx);
1489         return false;
1490 }
1491
1492 /*
1493   work out if we are a Global Catalog server for the domain of the current open ldb
1494 */
1495 bool samdb_is_gc(struct ldb_context *ldb)
1496 {
1497         const char *attrs[] = { "options", NULL };
1498         int ret, options;
1499         struct ldb_result *res;
1500         TALLOC_CTX *tmp_ctx;
1501
1502         tmp_ctx = talloc_new(ldb);
1503         if (tmp_ctx == NULL) {
1504                 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1505                 return false;
1506         }
1507
1508         /* Query cn=ntds settings,.... */
1509         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1510         if (ret) {
1511                 talloc_free(tmp_ctx);
1512                 return false;
1513         }
1514         if (res->count != 1) {
1515                 talloc_free(tmp_ctx);
1516                 return false;
1517         }
1518
1519         options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1520         talloc_free(tmp_ctx);
1521
1522         /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1523         if (options & 0x000000001) {
1524                 return true;
1525         }
1526         return false;
1527 }
1528
1529 /* Find a domain object in the parents of a particular DN.  */
1530 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1531                                    struct ldb_dn **parent_dn, const char **errstring)
1532 {
1533         TALLOC_CTX *local_ctx;
1534         struct ldb_dn *sdn = dn;
1535         struct ldb_result *res = NULL;
1536         int ret = 0;
1537         const char *attrs[] = { NULL };
1538
1539         local_ctx = talloc_new(mem_ctx);
1540         if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1541
1542         while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1543                 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1544                                  "(|(objectClass=domain)(objectClass=builtinDomain))");
1545                 if (ret == LDB_SUCCESS) {
1546                         if (res->count == 1) {
1547                                 break;
1548                         }
1549                 } else {
1550                         break;
1551                 }
1552         }
1553
1554         if (ret != LDB_SUCCESS) {
1555                 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1556                                              ldb_dn_get_linearized(dn),
1557                                              ldb_dn_get_linearized(sdn),
1558                                              ldb_errstring(ldb));
1559                 talloc_free(local_ctx);
1560                 return ret;
1561         }
1562         if (res->count != 1) {
1563                 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1564                                              ldb_dn_get_linearized(dn));
1565                 DEBUG(0,(__location__ ": %s\n", *errstring));
1566                 talloc_free(local_ctx);
1567                 return LDB_ERR_CONSTRAINT_VIOLATION;
1568         }
1569
1570         *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1571         talloc_free(local_ctx);
1572         return ret;
1573 }
1574
1575
1576 /*
1577   set the user password using plaintext, obeying any user or domain
1578   password restrictions
1579
1580   note that this function doesn't actually store the result in the
1581   database, it just fills in the "mod" structure with ldb modify
1582   elements to setup the correct change when samdb_replace() is
1583   called. This allows the caller to combine the change with other
1584   changes (as is needed by some of the set user info levels)
1585
1586   The caller should probably have a transaction wrapping this
1587 */
1588 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1589                             struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
1590                             struct ldb_message *mod,
1591                             const DATA_BLOB *new_password,
1592                             struct samr_Password *param_lmNewHash,
1593                             struct samr_Password *param_ntNewHash,
1594                             bool user_change,
1595                             enum samPwdChangeReason *reject_reason,
1596                             struct samr_DomInfo1 **_dominfo)
1597 {
1598         const char * const user_attrs[] = { "userAccountControl",
1599                                             "lmPwdHistory",
1600                                             "ntPwdHistory", 
1601                                             "dBCSPwd", "unicodePwd", 
1602                                             "objectSid", 
1603                                             "pwdLastSet", NULL };
1604         const char * const domain_attrs[] = { "minPwdLength", "pwdProperties",
1605                                               "pwdHistoryLength",
1606                                               "maxPwdAge", "minPwdAge", NULL };
1607         NTTIME pwdLastSet;
1608         uint32_t minPwdLength, pwdProperties, pwdHistoryLength;
1609         int64_t maxPwdAge, minPwdAge;
1610         uint32_t userAccountControl;
1611         struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory,
1612                 *lmPwdHash, *ntPwdHash, *lmNewHash, *ntNewHash;
1613         struct samr_Password local_lmNewHash, local_ntNewHash;
1614         int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1615         struct dom_sid *domain_sid;
1616         struct ldb_message **res;
1617         bool restrictions;
1618         int count;
1619         time_t now = time(NULL);
1620         NTTIME now_nt;
1621         int i;
1622
1623         /* we need to know the time to compute password age */
1624         unix_to_nt_time(&now_nt, now);
1625
1626         /* pull all the user parameters */
1627         count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1628         if (count != 1) {
1629                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1630         }
1631         userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1632         sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1633                                          "lmPwdHistory", &sambaLMPwdHistory);
1634         sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1635                                          "ntPwdHistory", &sambaNTPwdHistory);
1636         lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1637         ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1638         pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1639
1640         /* Copy parameters */
1641         lmNewHash = param_lmNewHash;
1642         ntNewHash = param_ntNewHash;
1643
1644         /* Only non-trust accounts have restrictions (possibly this
1645          * test is the wrong way around, but I like to be restrictive
1646          * if possible */
1647         restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1648                                                |UF_WORKSTATION_TRUST_ACCOUNT
1649                                                |UF_SERVER_TRUST_ACCOUNT)); 
1650
1651         if (domain_dn != NULL) {
1652                 /* pull the domain parameters */
1653                 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res,
1654                                                                 domain_attrs);
1655                 if (count != 1) {
1656                         DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n", 
1657                                   ldb_dn_get_linearized(domain_dn),
1658                                   ldb_dn_get_linearized(user_dn)));
1659                         return NT_STATUS_NO_SUCH_DOMAIN;
1660                 }
1661         } else {
1662                 /* work out the domain sid, and pull the domain from there */
1663                 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0],
1664                                                                 "objectSid");
1665                 if (domain_sid == NULL) {
1666                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1667                 }
1668
1669                 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs, 
1670                                 "(objectSid=%s)",
1671                                 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1672                 if (count != 1) {
1673                         DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n", 
1674                                   dom_sid_string(mem_ctx, domain_sid),
1675                                   ldb_dn_get_linearized(user_dn)));
1676                         return NT_STATUS_NO_SUCH_DOMAIN;
1677                 }
1678         }
1679
1680         minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1681         pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1682         pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1683         maxPwdAge = samdb_result_int64(res[0], "maxPwdAge", 0);
1684         minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1685
1686         if ((userAccountControl & UF_PASSWD_NOTREQD) != 0) {
1687                 /* see [MS-ADTS] 2.2.15 */
1688                 minPwdLength = 0;
1689         }
1690
1691         if (_dominfo != NULL) {
1692                 struct samr_DomInfo1 *dominfo;
1693                 /* on failure we need to fill in the reject reasons */
1694                 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1695                 if (dominfo == NULL) {
1696                         return NT_STATUS_NO_MEMORY;
1697                 }
1698                 dominfo->min_password_length     = minPwdLength;
1699                 dominfo->password_properties     = pwdProperties;
1700                 dominfo->password_history_length = pwdHistoryLength;
1701                 dominfo->max_password_age        = maxPwdAge;
1702                 dominfo->min_password_age        = minPwdAge;
1703                 *_dominfo = dominfo;
1704         }
1705
1706         if ((restrictions != 0) && (new_password != 0)) {
1707                 char *new_pass;
1708
1709                 /* checks if the "minPwdLength" property is satisfied */
1710                 if ((restrictions != 0)
1711                         && (minPwdLength > utf16_len_n(
1712                                 new_password->data, new_password->length)/2)) {
1713                         if (reject_reason) {
1714                                 *reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
1715                         }
1716                         return NT_STATUS_PASSWORD_RESTRICTION;
1717                 }
1718
1719                 /* Create the NT hash */
1720                 mdfour(local_ntNewHash.hash, new_password->data,
1721                                                         new_password->length);
1722
1723                 ntNewHash = &local_ntNewHash;
1724
1725                 /* Only check complexity if we can convert it at all.  Assuming unconvertable passwords are 'strong' */
1726                 if (convert_string_talloc_convenience(mem_ctx,
1727                           lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")),
1728                           CH_UTF16, CH_UNIX,
1729                           new_password->data, new_password->length,
1730                           (void **)&new_pass, NULL, false)) {
1731
1732                         /* checks the password complexity */
1733                         if ((restrictions != 0)
1734                                 && ((pwdProperties
1735                                         & DOMAIN_PASSWORD_COMPLEX) != 0)
1736                                 && (!check_password_quality(new_pass))) {
1737                                 if (reject_reason) {
1738                                         *reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
1739                                 }
1740                                 return NT_STATUS_PASSWORD_RESTRICTION;
1741                         }
1742
1743                         /* compute the new lm hashes (for checking history - case insenitivly!) */
1744                         if (E_deshash(new_pass, local_lmNewHash.hash)) {
1745                                 lmNewHash = &local_lmNewHash;
1746                         }
1747                 }
1748         }
1749
1750         if ((restrictions != 0) && user_change) {
1751                 /* are all password changes disallowed? */
1752                 if ((pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) != 0) {
1753                         if (reject_reason) {
1754                                 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1755                         }
1756                         return NT_STATUS_PASSWORD_RESTRICTION;
1757                 }
1758
1759                 /* can this user change the password? */
1760                 if ((userAccountControl & UF_PASSWD_CANT_CHANGE) != 0) {
1761                         if (reject_reason) {
1762                                 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1763                         }
1764                         return NT_STATUS_PASSWORD_RESTRICTION;
1765                 }
1766
1767                 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
1768                 if (pwdLastSet - minPwdAge > now_nt) {
1769                         if (reject_reason) {
1770                                 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1771                         }
1772                         return NT_STATUS_PASSWORD_RESTRICTION;
1773                 }
1774
1775                 /* check the immediately past password */
1776                 if (pwdHistoryLength > 0) {
1777                         if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash,
1778                                         lmPwdHash->hash, 16) == 0) {
1779                                 if (reject_reason) {
1780                                         *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1781                                 }
1782                                 return NT_STATUS_PASSWORD_RESTRICTION;
1783                         }
1784                         if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash,
1785                                         ntPwdHash->hash, 16) == 0) {
1786                                 if (reject_reason) {
1787                                         *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1788                                 }
1789                                 return NT_STATUS_PASSWORD_RESTRICTION;
1790                         }
1791                 }
1792
1793                 /* check the password history */
1794                 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len,
1795                                                         pwdHistoryLength);
1796                 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len,
1797                                                         pwdHistoryLength);
1798
1799                 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1800                         if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash,
1801                                         16) == 0) {
1802                                 if (reject_reason) {
1803                                         *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1804                                 }
1805                                 return NT_STATUS_PASSWORD_RESTRICTION;
1806                         }
1807                 }
1808                 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1809                         if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash,
1810                                          16) == 0) {
1811                                 if (reject_reason) {
1812                                         *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1813                                 }
1814                                 return NT_STATUS_PASSWORD_RESTRICTION;
1815                         }
1816                 }
1817         }
1818
1819 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1820
1821         /* the password is acceptable. Start forming the new fields */
1822         if (new_password != NULL) {
1823                 /* if we know the cleartext UTF16 password, then set it.
1824                  * Modules in ldb will set all the appropriate
1825                  * hashes */
1826                 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
1827         } else {
1828                 /* We don't have the cleartext, so delete the old one
1829                  * and set what we have of the hashes */
1830                 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword"));
1831
1832                 if (lmNewHash) {
1833                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1834                 } else {
1835                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1836                 }
1837
1838                 if (ntNewHash) {
1839                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1840                 } else {
1841                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1842                 }
1843         }
1844
1845         if (reject_reason) {
1846                 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1847         }
1848         return NT_STATUS_OK;
1849 }
1850
1851
1852 /*
1853  * Sets the user password using plaintext UTF16 (attribute "new_password") or
1854  * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
1855  * as parameter if it's a user change or not ("userChange"). The "rejectReason"
1856  * gives some more informations if the changed failed.
1857  *
1858  * This wrapper function for "samdb_set_password" takes a SID as input rather
1859  * than a user DN.
1860  *
1861  * This call encapsulates a new LDB transaction for changing the password;
1862  * therefore the user hasn't to start a new one.
1863  *
1864  * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
1865  *   NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
1866  *   NT_STATUS_PASSWORD_RESTRICTION
1867  */
1868 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1869                                 const struct dom_sid *user_sid,
1870                                 const DATA_BLOB *new_password,
1871                                 struct samr_Password *lmNewHash, 
1872                                 struct samr_Password *ntNewHash,
1873                                 bool user_change,
1874                                 enum samPwdChangeReason *reject_reason,
1875                                 struct samr_DomInfo1 **_dominfo) 
1876 {
1877         NTSTATUS nt_status;
1878         struct ldb_dn *user_dn;
1879         struct ldb_message *msg;
1880         int ret;
1881
1882         ret = ldb_transaction_start(ldb);
1883         if (ret != LDB_SUCCESS) {
1884                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
1885                 return NT_STATUS_TRANSACTION_ABORTED;
1886         }
1887
1888         user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
1889                                   "(&(objectSid=%s)(objectClass=user))", 
1890                                   ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1891         if (!user_dn) {
1892                 ldb_transaction_cancel(ldb);
1893                 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1894                           dom_sid_string(mem_ctx, user_sid)));
1895                 return NT_STATUS_NO_SUCH_USER;
1896         }
1897
1898         msg = ldb_msg_new(mem_ctx);
1899         if (msg == NULL) {
1900                 ldb_transaction_cancel(ldb);
1901                 return NT_STATUS_NO_MEMORY;
1902         }
1903
1904         msg->dn = ldb_dn_copy(msg, user_dn);
1905         if (!msg->dn) {
1906                 ldb_transaction_cancel(ldb);
1907                 return NT_STATUS_NO_MEMORY;
1908         }
1909
1910         nt_status = samdb_set_password(ldb, mem_ctx,
1911                                        user_dn, NULL,
1912                                        msg, new_password,
1913                                        lmNewHash, ntNewHash,
1914                                        user_change, /* This is a password set, not change */
1915                                        reject_reason, _dominfo);
1916         if (!NT_STATUS_IS_OK(nt_status)) {
1917                 ldb_transaction_cancel(ldb);
1918                 return nt_status;
1919         }
1920
1921         /* modify the samdb record */
1922         ret = samdb_replace(ldb, mem_ctx, msg);
1923         if (ret != LDB_SUCCESS) {
1924                 ldb_transaction_cancel(ldb);
1925                 return NT_STATUS_ACCESS_DENIED;
1926         }
1927
1928         ret = ldb_transaction_commit(ldb);
1929         if (ret != LDB_SUCCESS) {
1930                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1931                          ldb_dn_get_linearized(msg->dn),
1932                          ldb_errstring(ldb)));
1933                 return NT_STATUS_TRANSACTION_ABORTED;
1934         }
1935         return NT_STATUS_OK;
1936 }
1937
1938
1939 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
1940                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
1941 {
1942         struct ldb_message *msg;
1943         struct ldb_dn *basedn;
1944         const char *sidstr;
1945         int ret;
1946
1947         sidstr = dom_sid_string(mem_ctx, sid);
1948         NT_STATUS_HAVE_NO_MEMORY(sidstr);
1949
1950         /* We might have to create a ForeignSecurityPrincipal, even if this user
1951          * is in our own domain */
1952
1953         msg = ldb_msg_new(mem_ctx);
1954         if (msg == NULL) {
1955                 return NT_STATUS_NO_MEMORY;
1956         }
1957
1958         /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1959          * put the ForeignSecurityPrincipals? d_state->domain_dn does
1960          * not work, this is wrong for the Builtin domain, there's no
1961          * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
1962          */
1963
1964         basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1965                                  "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1966
1967         if (basedn == NULL) {
1968                 DEBUG(0, ("Failed to find DN for "
1969                           "ForeignSecurityPrincipal container\n"));
1970                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1971         }
1972
1973         /* add core elements to the ldb_message for the alias */
1974         msg->dn = ldb_dn_copy(mem_ctx, basedn);
1975         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1976                 return NT_STATUS_NO_MEMORY;
1977
1978         samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1979                              "objectClass",
1980                              "foreignSecurityPrincipal");
1981
1982         /* create the alias */
1983         ret = ldb_add(sam_ctx, msg);
1984         if (ret != 0) {
1985                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1986                          "record %s: %s\n", 
1987                          ldb_dn_get_linearized(msg->dn),
1988                          ldb_errstring(sam_ctx)));
1989                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1990         }
1991         *ret_dn = msg->dn;
1992         return NT_STATUS_OK;
1993 }
1994
1995
1996 /*
1997   Find the DN of a domain, assuming it to be a dotted.dns name
1998 */
1999
2000 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) 
2001 {
2002         int i;
2003         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2004         const char *binary_encoded;
2005         const char **split_realm;
2006         struct ldb_dn *dn;
2007
2008         if (!tmp_ctx) {
2009                 return NULL;
2010         }
2011
2012         split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2013         if (!split_realm) {
2014                 talloc_free(tmp_ctx);
2015                 return NULL;
2016         }
2017         dn = ldb_dn_new(mem_ctx, ldb, NULL);
2018         for (i=0; split_realm[i]; i++) {
2019                 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2020                 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2021                         DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2022                                   binary_encoded, ldb_dn_get_linearized(dn)));
2023                         talloc_free(tmp_ctx);
2024                         return NULL;
2025                 }
2026         }
2027         if (!ldb_dn_validate(dn)) {
2028                 DEBUG(2, ("Failed to validated DN %s\n",
2029                           ldb_dn_get_linearized(dn)));
2030                 return NULL;
2031         }
2032         return dn;
2033 }
2034 /*
2035   Find the DN of a domain, be it the netbios or DNS name 
2036 */
2037
2038 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
2039                                   const char *domain_name) 
2040 {
2041         const char * const domain_ref_attrs[] = {
2042                 "ncName", NULL
2043         };
2044         const char * const domain_ref2_attrs[] = {
2045                 NULL
2046         };
2047         struct ldb_result *res_domain_ref;
2048         char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2049         /* find the domain's DN */
2050         int ret_domain = ldb_search(ldb, mem_ctx,
2051                                             &res_domain_ref, 
2052                                             samdb_partitions_dn(ldb, mem_ctx), 
2053                                             LDB_SCOPE_ONELEVEL, 
2054                                             domain_ref_attrs,
2055                                             "(&(nETBIOSName=%s)(objectclass=crossRef))", 
2056                                             escaped_domain);
2057         if (ret_domain != 0) {
2058                 return NULL;
2059         }
2060
2061         if (res_domain_ref->count == 0) {
2062                 ret_domain = ldb_search(ldb, mem_ctx,
2063                                                 &res_domain_ref, 
2064                                                 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2065                                                 LDB_SCOPE_BASE,
2066                                                 domain_ref2_attrs,
2067                                                 "(objectclass=domain)");
2068                 if (ret_domain != 0) {
2069                         return NULL;
2070                 }
2071
2072                 if (res_domain_ref->count == 1) {
2073                         return res_domain_ref->msgs[0]->dn;
2074                 }
2075                 return NULL;
2076         }
2077
2078         if (res_domain_ref->count > 1) {
2079                 DEBUG(0,("Found %d records matching domain [%s]\n", 
2080                          ret_domain, domain_name));
2081                 return NULL;
2082         }
2083
2084         return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2085
2086 }
2087
2088
2089 /*
2090   use a GUID to find a DN
2091  */
2092 int dsdb_find_dn_by_guid(struct ldb_context *ldb, 
2093                          TALLOC_CTX *mem_ctx,
2094                          const char *guid_str, struct ldb_dn **dn)
2095 {
2096         int ret;
2097         struct ldb_result *res;
2098         const char *attrs[] = { NULL };
2099         struct ldb_request *search_req;
2100         char *expression;
2101         struct ldb_search_options_control *options;
2102
2103         expression = talloc_asprintf(mem_ctx, "objectGUID=%s", guid_str);
2104         if (!expression) {
2105                 DEBUG(0, (__location__ ": out of memory\n"));
2106                 return LDB_ERR_OPERATIONS_ERROR;
2107         }
2108
2109         res = talloc_zero(mem_ctx, struct ldb_result);
2110         if (!res) {
2111                 DEBUG(0, (__location__ ": out of memory\n"));
2112                 return LDB_ERR_OPERATIONS_ERROR;
2113         }
2114
2115         ret = ldb_build_search_req(&search_req, ldb, mem_ctx,
2116                                    ldb_get_default_basedn(ldb),
2117                                    LDB_SCOPE_SUBTREE,
2118                                    expression, attrs,
2119                                    NULL,
2120                                    res, ldb_search_default_callback,
2121                                    NULL);
2122         if (ret != LDB_SUCCESS) {
2123                 return ret;
2124         }
2125
2126         /* we need to cope with cross-partition links, so search for
2127            the GUID over all partitions */
2128         options = talloc(search_req, struct ldb_search_options_control);
2129         if (options == NULL) {
2130                 DEBUG(0, (__location__ ": out of memory\n"));
2131                 return LDB_ERR_OPERATIONS_ERROR;
2132         }
2133         options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2134
2135         ret = ldb_request_add_control(search_req, LDB_CONTROL_EXTENDED_DN_OID, true, NULL);
2136         if (ret != LDB_SUCCESS) {
2137                 return ret;
2138         }
2139
2140         ret = ldb_request_add_control(search_req,
2141                                       LDB_CONTROL_SEARCH_OPTIONS_OID,
2142                                       true, options);
2143         if (ret != LDB_SUCCESS) {
2144                 return ret;
2145         }
2146
2147         ret = ldb_request(ldb, search_req);
2148         if (ret != LDB_SUCCESS) {
2149                 return ret;
2150         }
2151
2152         ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
2153         if (ret != LDB_SUCCESS) {
2154                 return ret;
2155         }
2156
2157         /* this really should be exactly 1, but there is a bug in the
2158            partitions module that can return two here with the
2159            search_options control set */
2160         if (res->count < 1) {
2161                 return LDB_ERR_NO_SUCH_OBJECT;
2162         }
2163
2164         *dn = res->msgs[0]->dn;
2165
2166         return LDB_SUCCESS;
2167 }
2168
2169 /*
2170   search for attrs on one DN, allowing for deleted objects
2171  */
2172 int dsdb_search_dn_with_deleted(struct ldb_context *ldb,
2173                                 TALLOC_CTX *mem_ctx,
2174                                 struct ldb_result **_res,
2175                                 struct ldb_dn *basedn,
2176                                 const char * const *attrs)
2177 {
2178         int ret;
2179         struct ldb_request *req;
2180         TALLOC_CTX *tmp_ctx;
2181         struct ldb_result *res;
2182
2183         tmp_ctx = talloc_new(mem_ctx);
2184
2185         res = talloc_zero(tmp_ctx, struct ldb_result);
2186         if (!res) {
2187                 return LDB_ERR_OPERATIONS_ERROR;
2188         }
2189
2190         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2191                                    basedn,
2192                                    LDB_SCOPE_BASE,
2193                                    NULL,
2194                                    attrs,
2195                                    NULL,
2196                                    res,
2197                                    ldb_search_default_callback,
2198                                    NULL);
2199         if (ret != LDB_SUCCESS) {
2200                 talloc_free(tmp_ctx);
2201                 return ret;
2202         }
2203
2204         ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2205         if (ret != LDB_SUCCESS) {
2206                 return ret;
2207         }
2208
2209         ret = ldb_request(ldb, req);
2210         if (ret == LDB_SUCCESS) {
2211                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2212         }
2213
2214         talloc_free(req);
2215         *_res = talloc_steal(mem_ctx, res);
2216         return ret;
2217 }
2218
2219
2220 /*
2221   use a DN to find a GUID
2222  */
2223 int dsdb_find_guid_by_dn(struct ldb_context *ldb, 
2224                          struct ldb_dn *dn, struct GUID *guid)
2225 {
2226         int ret;
2227         struct ldb_result *res;
2228         const char *attrs[] = { "objectGUID", NULL };
2229         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2230
2231         ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
2232         if (ret != LDB_SUCCESS) {
2233                 talloc_free(tmp_ctx);
2234                 return ret;
2235         }
2236         if (res->count < 1) {
2237                 talloc_free(tmp_ctx);
2238                 return LDB_ERR_NO_SUCH_OBJECT;
2239         }
2240         *guid = samdb_result_guid(res->msgs[0], "objectGUID");
2241         talloc_free(tmp_ctx);
2242         return LDB_SUCCESS;
2243 }
2244
2245 /*
2246   use a DN to find a SID
2247  */
2248 int dsdb_find_sid_by_dn(struct ldb_context *ldb, 
2249                         struct ldb_dn *dn, struct dom_sid *sid)
2250 {
2251         int ret;
2252         struct ldb_result *res;
2253         const char *attrs[] = { "objectSID", NULL };
2254         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2255         struct dom_sid *s;
2256
2257         ZERO_STRUCTP(sid);
2258
2259         ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
2260         if (ret != LDB_SUCCESS) {
2261                 talloc_free(tmp_ctx);
2262                 return ret;
2263         }
2264         if (res->count < 1) {
2265                 talloc_free(tmp_ctx);
2266                 return LDB_ERR_NO_SUCH_OBJECT;
2267         }
2268         s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSID");
2269         if (s == NULL) {
2270                 talloc_free(tmp_ctx);
2271                 return LDB_ERR_NO_SUCH_OBJECT;
2272         }
2273         *sid = *s;
2274         talloc_free(tmp_ctx);
2275         return LDB_SUCCESS;
2276 }
2277
2278
2279
2280 /*
2281   load a repsFromTo blob list for a given partition GUID
2282   attr must be "repsFrom" or "repsTo"
2283  */
2284 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2285                      const char *attr, struct repsFromToBlob **r, uint32_t *count)
2286 {
2287         const char *attrs[] = { attr, NULL };
2288         struct ldb_result *res = NULL;
2289         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2290         int i;
2291         struct ldb_message_element *el;
2292
2293         *r = NULL;
2294         *count = 0;
2295
2296         if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2297             res->count < 1) {
2298                 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2299                 talloc_free(tmp_ctx);
2300                 return WERR_DS_DRA_INTERNAL_ERROR;
2301         }
2302
2303         el = ldb_msg_find_element(res->msgs[0], attr);
2304         if (el == NULL) {
2305                 /* it's OK to be empty */
2306                 talloc_free(tmp_ctx);
2307                 return WERR_OK;
2308         }
2309
2310         *count = el->num_values;
2311         *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2312         if (*r == NULL) {
2313                 talloc_free(tmp_ctx);
2314                 return WERR_DS_DRA_INTERNAL_ERROR;
2315         }
2316
2317         for (i=0; i<(*count); i++) {
2318                 enum ndr_err_code ndr_err;
2319                 ndr_err = ndr_pull_struct_blob(&el->values[i], 
2320                                                mem_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2321                                                &(*r)[i], 
2322                                                (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2323                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2324                         talloc_free(tmp_ctx);
2325                         return WERR_DS_DRA_INTERNAL_ERROR;
2326                 }
2327         }
2328
2329         talloc_free(tmp_ctx);
2330         
2331         return WERR_OK;
2332 }
2333
2334 /*
2335   save the repsFromTo blob list for a given partition GUID
2336   attr must be "repsFrom" or "repsTo"
2337  */
2338 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2339                      const char *attr, struct repsFromToBlob *r, uint32_t count)
2340 {
2341         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2342         struct ldb_message *msg;
2343         struct ldb_message_element *el;
2344         int i;
2345
2346         msg = ldb_msg_new(tmp_ctx);
2347         msg->dn = dn;
2348         if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2349                 goto failed;
2350         }
2351
2352         el->values = talloc_array(msg, struct ldb_val, count);
2353         if (!el->values) {
2354                 goto failed;
2355         }
2356
2357         for (i=0; i<count; i++) {
2358                 struct ldb_val v;
2359                 enum ndr_err_code ndr_err;
2360
2361                 ndr_err = ndr_push_struct_blob(&v, tmp_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2362                                                &r[i], 
2363                                                (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2364                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2365                         goto failed;
2366                 }
2367
2368                 el->num_values++;
2369                 el->values[i] = v;
2370         }
2371
2372         if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2373                 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2374                 goto failed;
2375         }
2376
2377         talloc_free(tmp_ctx);
2378         
2379         return WERR_OK;
2380
2381 failed:
2382         talloc_free(tmp_ctx);
2383         return WERR_DS_DRA_INTERNAL_ERROR;
2384 }
2385
2386
2387 /*
2388   load the uSNHighest attribute from the @REPLCHANGED object for a
2389   partition
2390  */
2391 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t *uSN)
2392 {
2393         struct ldb_request *req;
2394         int ret;
2395         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2396         struct dsdb_control_current_partition *p_ctrl;
2397         struct ldb_result *res;
2398
2399         res = talloc_zero(tmp_ctx, struct ldb_result);
2400         if (!res) {
2401                 talloc_free(tmp_ctx);
2402                 return LDB_ERR_OPERATIONS_ERROR;
2403         }
2404
2405         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2406                                    ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2407                                    LDB_SCOPE_BASE,
2408                                    NULL, NULL,
2409                                    NULL,
2410                                    res, ldb_search_default_callback,
2411                                    NULL);
2412         if (ret != LDB_SUCCESS) {
2413                 talloc_free(tmp_ctx);
2414                 return ret;
2415         }
2416
2417         p_ctrl = talloc(req, struct dsdb_control_current_partition);
2418         if (p_ctrl == NULL) {
2419                 talloc_free(res);
2420                 return LDB_ERR_OPERATIONS_ERROR;
2421         }
2422         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2423         p_ctrl->dn = dn;
2424         
2425
2426         ret = ldb_request_add_control(req,
2427                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
2428                                       false, p_ctrl);
2429         if (ret != LDB_SUCCESS) {
2430                 talloc_free(tmp_ctx);
2431                 return ret;
2432         }
2433         
2434         /* Run the new request */
2435         ret = ldb_request(ldb, req);
2436         
2437         if (ret == LDB_SUCCESS) {
2438                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2439         }
2440
2441         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2442                 /* it hasn't been created yet, which means
2443                    an implicit value of zero */
2444                 *uSN = 0;
2445                 talloc_free(tmp_ctx);
2446                 return LDB_SUCCESS;
2447         }
2448
2449         if (ret != LDB_SUCCESS) {
2450                 talloc_free(tmp_ctx);
2451                 return ret;
2452         }
2453
2454         if (res->count < 1) {
2455                 *uSN = 0;
2456         } else {
2457                 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2458         }
2459
2460         talloc_free(tmp_ctx);
2461
2462         return LDB_SUCCESS;     
2463 }
2464
2465 /*
2466   save the uSNHighest attribute in the @REPLCHANGED object for a
2467   partition
2468  */
2469 int dsdb_save_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t uSN)
2470 {
2471         struct ldb_request *req;
2472         struct ldb_message *msg;
2473         struct dsdb_control_current_partition *p_ctrl;
2474         int ret;
2475
2476         msg = ldb_msg_new(ldb);
2477         if (msg == NULL) {
2478                 return LDB_ERR_OPERATIONS_ERROR;
2479         }
2480
2481         msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
2482         if (msg->dn == NULL) {
2483                 talloc_free(msg);
2484                 return LDB_ERR_OPERATIONS_ERROR;
2485         }
2486         
2487         ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
2488         if (ret != LDB_SUCCESS) {
2489                 talloc_free(msg);
2490                 return ret;
2491         }
2492         msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
2493         
2494
2495         p_ctrl = talloc(msg, struct dsdb_control_current_partition);
2496         if (p_ctrl == NULL) {
2497                 talloc_free(msg);
2498                 return LDB_ERR_OPERATIONS_ERROR;
2499         }
2500         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2501         p_ctrl->dn = dn;
2502
2503         ret = ldb_build_mod_req(&req, ldb, msg,
2504                                 msg,
2505                                 NULL,
2506                                 NULL, ldb_op_default_callback,
2507                                 NULL);
2508 again:
2509         if (ret != LDB_SUCCESS) {
2510                 talloc_free(msg);
2511                 return ret;
2512         }
2513         
2514         ret = ldb_request_add_control(req,
2515                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
2516                                       false, p_ctrl);
2517         if (ret != LDB_SUCCESS) {
2518                 talloc_free(msg);
2519                 return ret;
2520         }
2521         
2522         /* Run the new request */
2523         ret = ldb_request(ldb, req);
2524         
2525         if (ret == LDB_SUCCESS) {
2526                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2527         }
2528         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2529                 ret = ldb_build_add_req(&req, ldb, msg,
2530                                         msg,
2531                                         NULL,
2532                                         NULL, ldb_op_default_callback,
2533                                         NULL);
2534                 goto again;
2535         }
2536         
2537         talloc_free(msg);
2538         
2539         return ret;
2540 }
2541
2542 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2543                                                    const struct drsuapi_DsReplicaCursor2 *c2)
2544 {
2545         return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2546 }
2547
2548 /*
2549   see if we are a RODC
2550
2551   TODO: This should take a sam_ctx, and lookup the right object (with
2552   a cache)
2553 */
2554 bool samdb_rodc(struct loadparm_context *lp_ctx)
2555 {
2556         return lp_parm_bool(lp_ctx, NULL, "repl", "RODC", false);
2557 }
2558
2559
2560 /*
2561   return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1 
2562
2563   flags are DS_NTDS_OPTION_*
2564 */
2565 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2566 {
2567         TALLOC_CTX *tmp_ctx;
2568         const char *attrs[] = { "options", NULL };
2569         int ret;
2570         struct ldb_result *res;
2571
2572         tmp_ctx = talloc_new(ldb);
2573         if (tmp_ctx == NULL) {
2574                 goto failed;
2575         }
2576
2577         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2578         if (ret) {
2579                 goto failed;
2580         }
2581
2582         if (res->count != 1) {
2583                 goto failed;
2584         }
2585
2586         *options = samdb_result_uint(res->msgs[0], "options", 0);
2587
2588         talloc_free(tmp_ctx);
2589
2590         return LDB_SUCCESS;
2591
2592 failed:
2593         DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
2594         talloc_free(tmp_ctx);
2595         return LDB_ERR_NO_SUCH_OBJECT;
2596 }