Merge branch 'master' of ssh://git.samba.org/data/git/samba into regsrv
[ab/samba.git/.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.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 "dsdb/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
40 /*
41   search the sam for the specified attributes in a specific domain, filter on
42   objectSid being in domain_sid.
43 */
44 int samdb_search_domain(struct ldb_context *sam_ldb,
45                         TALLOC_CTX *mem_ctx, 
46                         struct ldb_dn *basedn,
47                         struct ldb_message ***res,
48                         const char * const *attrs,
49                         const struct dom_sid *domain_sid,
50                         const char *format, ...)  _PRINTF_ATTRIBUTE(7,8)
51 {
52         va_list ap;
53         int i, count;
54
55         va_start(ap, format);
56         count = gendb_search_v(sam_ldb, mem_ctx, basedn,
57                                res, attrs, format, ap);
58         va_end(ap);
59
60         i=0;
61
62         while (i<count) {
63                 struct dom_sid *entry_sid;
64
65                 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
66
67                 if ((entry_sid == NULL) ||
68                     (!dom_sid_in_domain(domain_sid, entry_sid))) {
69                         /* Delete that entry from the result set */
70                         (*res)[i] = (*res)[count-1];
71                         count -= 1;
72                         talloc_free(entry_sid);
73                         continue;
74                 }
75                 talloc_free(entry_sid);
76                 i += 1;
77         }
78
79         return count;
80 }
81
82 /*
83   search the sam for a single string attribute in exactly 1 record
84 */
85 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
86                                   TALLOC_CTX *mem_ctx,
87                                   struct ldb_dn *basedn,
88                                   const char *attr_name,
89                                   const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
90 {
91         int count;
92         const char *attrs[2] = { NULL, NULL };
93         struct ldb_message **res = NULL;
94
95         attrs[0] = attr_name;
96
97         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
98         if (count > 1) {                
99                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
100                          attr_name, format, count));
101         }
102         if (count != 1) {
103                 talloc_free(res);
104                 return NULL;
105         }
106
107         return samdb_result_string(res[0], attr_name, NULL);
108 }
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 uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
441  * indicate an account doesn't expire.
442  *
443  * When Windows initially creates an account, it sets
444  * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF).  However,
445  * when changing from an account having a specific expiration date to
446  * that account never expiring, it sets accountExpires = 0.
447  *
448  * Consolidate that logic here to allow clearer logic for account expiry in
449  * the rest of the code.
450  */
451 NTTIME samdb_result_account_expires(struct ldb_message *msg)
452 {
453         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
454                                                  0);
455
456         if (ret == 0)
457                 ret = 0x7FFFFFFFFFFFFFFFULL;
458
459         return ret;
460 }
461
462 /*
463   pull a uint64_t from a result set. 
464 */
465 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
466 {
467         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
468 }
469
470
471 /*
472   construct the allow_password_change field from the PwdLastSet attribute and the 
473   domain password settings
474 */
475 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb, 
476                                           TALLOC_CTX *mem_ctx, 
477                                           struct ldb_dn *domain_dn, 
478                                           struct ldb_message *msg, 
479                                           const char *attr)
480 {
481         uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
482         int64_t minPwdAge;
483
484         if (attr_time == 0) {
485                 return 0;
486         }
487
488         minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
489
490         /* yes, this is a -= not a += as minPwdAge is stored as the negative
491            of the number of 100-nano-seconds */
492         attr_time -= minPwdAge;
493
494         return attr_time;
495 }
496
497 /*
498   construct the force_password_change field from the PwdLastSet
499   attribute, the userAccountControl and the domain password settings
500 */
501 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb, 
502                                           TALLOC_CTX *mem_ctx, 
503                                           struct ldb_dn *domain_dn, 
504                                           struct ldb_message *msg)
505 {
506         uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
507         uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
508         int64_t maxPwdAge;
509
510         /* Machine accounts don't expire, and there is a flag for 'no expiry' */
511         if (!(userAccountControl & UF_NORMAL_ACCOUNT)
512             || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
513                 return 0x7FFFFFFFFFFFFFFFULL;
514         }
515
516         if (attr_time == 0) {
517                 return 0;
518         }
519
520         maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
521         if (maxPwdAge == 0) {
522                 return 0x7FFFFFFFFFFFFFFFULL;
523         } else {
524                 attr_time -= maxPwdAge;
525         }
526
527         return attr_time;
528 }
529
530 /*
531   pull a samr_Password structutre from a result set. 
532 */
533 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
534 {
535         struct samr_Password *hash = NULL;
536         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
537         if (val && (val->length >= sizeof(hash->hash))) {
538                 hash = talloc(mem_ctx, struct samr_Password);
539                 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
540         }
541         return hash;
542 }
543
544 /*
545   pull an array of samr_Password structutres from a result set. 
546 */
547 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
548                            const char *attr, struct samr_Password **hashes)
549 {
550         uint_t count = 0;
551         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
552         int i;
553
554         *hashes = NULL;
555         if (!val) {
556                 return 0;
557         }
558         count = val->length / 16;
559         if (count == 0) {
560                 return 0;
561         }
562
563         *hashes = talloc_array(mem_ctx, struct samr_Password, count);
564         if (! *hashes) {
565                 return 0;
566         }
567
568         for (i=0;i<count;i++) {
569                 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
570         }
571
572         return count;
573 }
574
575 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg, 
576                                 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd) 
577 {
578         struct samr_Password *lmPwdHash, *ntPwdHash;
579         if (nt_pwd) {
580                 int num_nt;
581                 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
582                 if (num_nt == 0) {
583                         *nt_pwd = NULL;
584                 } else if (num_nt > 1) {
585                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
586                 } else {
587                         *nt_pwd = &ntPwdHash[0];
588                 }
589         }
590         if (lm_pwd) {
591                 /* Ensure that if we have turned off LM
592                  * authentication, that we never use the LM hash, even
593                  * if we store it */
594                 if (lp_lanman_auth(lp_ctx)) {
595                         int num_lm;
596                         num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
597                         if (num_lm == 0) {
598                                 *lm_pwd = NULL;
599                         } else if (num_lm > 1) {
600                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
601                         } else {
602                                 *lm_pwd = &lmPwdHash[0];
603                         }
604                 } else {
605                         *lm_pwd = NULL;
606                 }
607         }
608         return NT_STATUS_OK;
609 }
610
611 /*
612   pull a samr_LogonHours structutre from a result set. 
613 */
614 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
615 {
616         struct samr_LogonHours hours;
617         const int units_per_week = 168;
618         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
619         ZERO_STRUCT(hours);
620         hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
621         if (!hours.bits) {
622                 return hours;
623         }
624         hours.units_per_week = units_per_week;
625         memset(hours.bits, 0xFF, units_per_week);
626         if (val) {
627                 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
628         }
629         return hours;
630 }
631
632 /*
633   pull a set of account_flags from a result set. 
634
635   This requires that the attributes: 
636    pwdLastSet
637    userAccountControl
638   be included in 'msg'
639 */
640 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
641                                  struct ldb_message *msg, struct ldb_dn *domain_dn)
642 {
643         uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
644         uint32_t acct_flags = samdb_uf2acb(userAccountControl); 
645         NTTIME must_change_time;
646         NTTIME now;
647         
648         must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx, 
649                                                               domain_dn, msg);
650         
651         /* Test account expire time */
652         unix_to_nt_time(&now, time(NULL));
653         /* check for expired password */
654         if (must_change_time < now) {
655                 acct_flags |= ACB_PW_EXPIRED;
656         }
657         return acct_flags;
658 }
659
660
661 /* Find an attribute, with a particular value */
662
663 /* The current callers of this function expect a very specific
664  * behaviour: In particular, objectClass subclass equivilance is not
665  * wanted.  This means that we should not lookup the schema for the
666  * comparison function */
667 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb, 
668                                                  const struct ldb_message *msg, 
669                                                  const char *name, const char *value)
670 {
671         int i;
672         struct ldb_message_element *el = ldb_msg_find_element(msg, name);
673
674         if (!el) {
675                 return NULL;
676         }
677
678         for (i=0;i<el->num_values;i++) {
679                 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
680                         return el;
681                 }
682         }
683
684         return NULL;
685 }
686
687 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
688 {
689         if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
690                 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
691         }
692         return LDB_SUCCESS;
693 }
694
695 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
696 {
697         struct ldb_message_element *el;
698
699         el = ldb_msg_find_element(msg, name);
700         if (el) {
701                 return LDB_SUCCESS;
702         }
703                 
704         return samdb_msg_add_string(ldb, msg, msg, name, set_value);
705 }
706
707
708
709 /*
710   add a string element to a message
711 */
712 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
713                          const char *attr_name, const char *str)
714 {
715         char *s = talloc_strdup(mem_ctx, str);
716         char *a = talloc_strdup(mem_ctx, attr_name);
717         if (s == NULL || a == NULL) {
718                 return LDB_ERR_OPERATIONS_ERROR;
719         }
720         return ldb_msg_add_string(msg, a, s);
721 }
722
723 /*
724   add a dom_sid element to a message
725 */
726 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
727                          const char *attr_name, struct dom_sid *sid)
728 {
729         struct ldb_val v;
730         enum ndr_err_code ndr_err;
731
732         ndr_err = ndr_push_struct_blob(&v, mem_ctx, 
733                                        lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
734                                        sid,
735                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
736         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
737                 return -1;
738         }
739         return ldb_msg_add_value(msg, attr_name, &v, NULL);
740 }
741
742
743 /*
744   add a delete element operation to a message
745 */
746 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
747                          const char *attr_name)
748 {
749         /* we use an empty replace rather than a delete, as it allows for 
750            samdb_replace() to be used everywhere */
751         return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
752 }
753
754 /*
755   add a add attribute value to a message
756 */
757 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
758                          const char *attr_name, const char *value)
759 {
760         struct ldb_message_element *el;
761         char *a, *v;
762         int ret;
763         a = talloc_strdup(mem_ctx, attr_name);
764         if (a == NULL)
765                 return -1;
766         v = talloc_strdup(mem_ctx, value);
767         if (v == NULL)
768                 return -1;
769         ret = ldb_msg_add_string(msg, a, v);
770         if (ret != 0)
771                 return ret;
772         el = ldb_msg_find_element(msg, a);
773         if (el == NULL)
774                 return -1;
775         el->flags = LDB_FLAG_MOD_ADD;
776         return 0;
777 }
778
779 /*
780   add a delete attribute value to a message
781 */
782 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
783                          const char *attr_name, const char *value)
784 {
785         struct ldb_message_element *el;
786         char *a, *v;
787         int ret;
788         a = talloc_strdup(mem_ctx, attr_name);
789         if (a == NULL)
790                 return -1;
791         v = talloc_strdup(mem_ctx, value);
792         if (v == NULL)
793                 return -1;
794         ret = ldb_msg_add_string(msg, a, v);
795         if (ret != 0)
796                 return ret;
797         el = ldb_msg_find_element(msg, a);
798         if (el == NULL)
799                 return -1;
800         el->flags = LDB_FLAG_MOD_DELETE;
801         return 0;
802 }
803
804 /*
805   add a int element to a message
806 */
807 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
808                        const char *attr_name, int v)
809 {
810         const char *s = talloc_asprintf(mem_ctx, "%d", v);
811         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
812 }
813
814 /*
815   add a uint_t element to a message
816 */
817 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
818                        const char *attr_name, uint_t v)
819 {
820         const char *s = talloc_asprintf(mem_ctx, "%u", v);
821         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
822 }
823
824 /*
825   add a (signed) int64_t element to a message
826 */
827 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
828                         const char *attr_name, int64_t v)
829 {
830         const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
831         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
832 }
833
834 /*
835   add a uint64_t element to a message
836 */
837 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
838                         const char *attr_name, uint64_t v)
839 {
840         const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
841         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
842 }
843
844 /*
845   add a samr_Password element to a message
846 */
847 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
848                        const char *attr_name, struct samr_Password *hash)
849 {
850         struct ldb_val val;
851         val.data = talloc_memdup(mem_ctx, hash->hash, 16);
852         if (!val.data) {
853                 return -1;
854         }
855         val.length = 16;
856         return ldb_msg_add_value(msg, attr_name, &val, NULL);
857 }
858
859 /*
860   add a samr_Password array to a message
861 */
862 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
863                          const char *attr_name, struct samr_Password *hashes, uint_t count)
864 {
865         struct ldb_val val;
866         int i;
867         val.data = talloc_array_size(mem_ctx, 16, count);
868         val.length = count*16;
869         if (!val.data) {
870                 return -1;
871         }
872         for (i=0;i<count;i++) {
873                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
874         }
875         return ldb_msg_add_value(msg, attr_name, &val, NULL);
876 }
877
878 /*
879   add a acct_flags element to a message
880 */
881 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
882                              const char *attr_name, uint32_t v)
883 {
884         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
885 }
886
887 /*
888   add a logon_hours element to a message
889 */
890 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
891                               const char *attr_name, struct samr_LogonHours *hours)
892 {
893         struct ldb_val val;
894         val.length = hours->units_per_week / 8;
895         val.data = hours->bits;
896         return ldb_msg_add_value(msg, attr_name, &val, NULL);
897 }
898
899 /*
900   add a general value element to a message
901 */
902 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
903                               const char *attr_name, const struct ldb_val *val)
904 {
905         return ldb_msg_add_value(msg, attr_name, val, NULL);
906 }
907
908 /*
909   sets a general value element to a message
910 */
911 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
912                         const char *attr_name, const struct ldb_val *val)
913 {
914         struct ldb_message_element *el;
915
916         el = ldb_msg_find_element(msg, attr_name);
917         if (el) {
918                 el->num_values = 0;
919         }
920         return ldb_msg_add_value(msg, attr_name, val, NULL);
921 }
922
923 /*
924   set a string element in a message
925 */
926 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
927                          const char *attr_name, const char *str)
928 {
929         struct ldb_message_element *el;
930
931         el = ldb_msg_find_element(msg, attr_name);
932         if (el) {
933                 el->num_values = 0;
934         }
935         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
936 }
937
938 /*
939   replace elements in a record
940 */
941 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
942 {
943         int i;
944
945         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
946         for (i=0;i<msg->num_elements;i++) {
947                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
948         }
949
950         /* modify the samdb record */
951         return ldb_modify(sam_ldb, msg);
952 }
953
954 /*
955   return a default security descriptor
956 */
957 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
958 {
959         struct security_descriptor *sd;
960
961         sd = security_descriptor_initialise(mem_ctx);
962
963         return sd;
964 }
965
966 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx) 
967 {
968         return ldb_get_default_basedn(sam_ctx);
969 }
970
971 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx) 
972 {
973         return ldb_get_config_basedn(sam_ctx);
974 }
975
976 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx) 
977 {
978         return ldb_get_schema_basedn(sam_ctx);
979 }
980
981 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx) 
982 {
983         return ldb_get_root_basedn(sam_ctx);
984 }
985
986 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
987 {
988         struct ldb_dn *new_dn;
989
990         new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
991         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
992                 talloc_free(new_dn);
993                 return NULL;
994         }
995         return new_dn;
996 }
997
998 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
999 {
1000         struct ldb_dn *new_dn;
1001
1002         new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1003         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1004                 talloc_free(new_dn);
1005                 return NULL;
1006         }
1007         return new_dn;
1008 }
1009
1010 /*
1011   work out the domain sid for the current open ldb
1012 */
1013 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1014 {
1015         TALLOC_CTX *tmp_ctx;
1016         const struct dom_sid *domain_sid;
1017         const char *attrs[] = {
1018                 "objectSid",
1019                 NULL
1020         };
1021         struct ldb_result *res;
1022         int ret;
1023
1024         /* see if we have a cached copy */
1025         domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1026         if (domain_sid) {
1027                 return domain_sid;
1028         }
1029
1030         tmp_ctx = talloc_new(ldb);
1031         if (tmp_ctx == NULL) {
1032                 goto failed;
1033         }
1034
1035         ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1036
1037         if (ret != LDB_SUCCESS) {
1038                 goto failed;
1039         }
1040         
1041         if (res->count != 1) {
1042                 goto failed;
1043         }
1044
1045         domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1046         if (domain_sid == NULL) {
1047                 goto failed;
1048         }
1049
1050         /* cache the domain_sid in the ldb */
1051         if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1052                 goto failed;
1053         }
1054
1055         talloc_steal(ldb, domain_sid);
1056         talloc_free(tmp_ctx);
1057
1058         return domain_sid;
1059
1060 failed:
1061         DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1062         talloc_free(tmp_ctx);
1063         return NULL;
1064 }
1065
1066 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1067 {
1068         TALLOC_CTX *tmp_ctx;
1069         struct dom_sid *dom_sid_new;
1070         struct dom_sid *dom_sid_old;
1071
1072         /* see if we have a cached copy */
1073         dom_sid_old = talloc_get_type(ldb_get_opaque(ldb, 
1074                                                      "cache.domain_sid"), struct dom_sid);
1075
1076         tmp_ctx = talloc_new(ldb);
1077         if (tmp_ctx == NULL) {
1078                 goto failed;
1079         }
1080
1081         dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1082         if (!dom_sid_new) {
1083                 goto failed;
1084         }
1085
1086         /* cache the domain_sid in the ldb */
1087         if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1088                 goto failed;
1089         }
1090
1091         talloc_steal(ldb, dom_sid_new);
1092         talloc_free(tmp_ctx);
1093         talloc_free(dom_sid_old);
1094
1095         return true;
1096
1097 failed:
1098         DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1099         talloc_free(tmp_ctx);
1100         return false;
1101 }
1102
1103 /* Obtain the short name of the flexible single master operator
1104  * (FSMO), such as the PDC Emulator */
1105 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
1106                              const char *attr)
1107 {
1108         /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1109         struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1110         const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1111         const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1112
1113         if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1114                 /* Ensure this matches the format.  This gives us a
1115                  * bit more confidence that a 'cn' value will be a
1116                  * ascii string */
1117                 return NULL;
1118         }
1119         if (val) {
1120                 return (char *)val->data;
1121         }
1122         return NULL;
1123 }
1124
1125 /*
1126   work out the ntds settings dn for the current open ldb
1127 */
1128 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1129 {
1130         TALLOC_CTX *tmp_ctx;
1131         const char *root_attrs[] = { "dsServiceName", NULL };
1132         int ret;
1133         struct ldb_result *root_res;
1134         struct ldb_dn *settings_dn;
1135         
1136         /* see if we have a cached copy */
1137         settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1138         if (settings_dn) {
1139                 return settings_dn;
1140         }
1141
1142         tmp_ctx = talloc_new(ldb);
1143         if (tmp_ctx == NULL) {
1144                 goto failed;
1145         }
1146         
1147
1148         ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1149         if (ret) {
1150                 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n", 
1151                          ldb_errstring(ldb)));
1152                 goto failed;
1153         }
1154
1155         if (root_res->count != 1) {
1156                 goto failed;
1157         }
1158
1159         settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1160
1161         /* cache the domain_sid in the ldb */
1162         if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1163                 goto failed;
1164         }
1165
1166         talloc_steal(ldb, settings_dn);
1167         talloc_free(tmp_ctx);
1168
1169         return settings_dn;
1170
1171 failed:
1172         DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1173         talloc_free(tmp_ctx);
1174         return NULL;
1175 }
1176
1177 /*
1178   work out the ntds settings invocationId for the current open ldb
1179 */
1180 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1181 {
1182         TALLOC_CTX *tmp_ctx;
1183         const char *attrs[] = { "invocationId", NULL };
1184         int ret;
1185         struct ldb_result *res;
1186         struct GUID *invocation_id;
1187         
1188         /* see if we have a cached copy */
1189         invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1190         if (invocation_id) {
1191                 return invocation_id;
1192         }
1193
1194         tmp_ctx = talloc_new(ldb);
1195         if (tmp_ctx == NULL) {
1196                 goto failed;
1197         }
1198
1199         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1200         if (ret) {
1201                 goto failed;
1202         }
1203
1204         if (res->count != 1) {
1205                 goto failed;
1206         }
1207
1208         invocation_id = talloc(tmp_ctx, struct GUID);
1209         if (!invocation_id) {
1210                 goto failed;
1211         }
1212
1213         *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1214
1215         /* cache the domain_sid in the ldb */
1216         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1217                 goto failed;
1218         }
1219
1220         talloc_steal(ldb, invocation_id);
1221         talloc_free(tmp_ctx);
1222
1223         return invocation_id;
1224
1225 failed:
1226         DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1227         talloc_free(tmp_ctx);
1228         return NULL;
1229 }
1230
1231 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1232 {
1233         TALLOC_CTX *tmp_ctx;
1234         struct GUID *invocation_id_new;
1235         struct GUID *invocation_id_old;
1236
1237         /* see if we have a cached copy */
1238         invocation_id_old = (struct GUID *)ldb_get_opaque(ldb, 
1239                                                          "cache.invocation_id");
1240
1241         tmp_ctx = talloc_new(ldb);
1242         if (tmp_ctx == NULL) {
1243                 goto failed;
1244         }
1245
1246         invocation_id_new = talloc(tmp_ctx, struct GUID);
1247         if (!invocation_id_new) {
1248                 goto failed;
1249         }
1250
1251         *invocation_id_new = *invocation_id_in;
1252
1253         /* cache the domain_sid in the ldb */
1254         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1255                 goto failed;
1256         }
1257
1258         talloc_steal(ldb, invocation_id_new);
1259         talloc_free(tmp_ctx);
1260         talloc_free(invocation_id_old);
1261
1262         return true;
1263
1264 failed:
1265         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1266         talloc_free(tmp_ctx);
1267         return false;
1268 }
1269
1270 /*
1271   work out the ntds settings objectGUID for the current open ldb
1272 */
1273 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1274 {
1275         TALLOC_CTX *tmp_ctx;
1276         const char *attrs[] = { "objectGUID", NULL };
1277         int ret;
1278         struct ldb_result *res;
1279         struct GUID *ntds_guid;
1280         
1281         /* see if we have a cached copy */
1282         ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1283         if (ntds_guid) {
1284                 return ntds_guid;
1285         }
1286
1287         tmp_ctx = talloc_new(ldb);
1288         if (tmp_ctx == NULL) {
1289                 goto failed;
1290         }
1291
1292         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1293         if (ret) {
1294                 goto failed;
1295         }
1296
1297         if (res->count != 1) {
1298                 goto failed;
1299         }
1300
1301         ntds_guid = talloc(tmp_ctx, struct GUID);
1302         if (!ntds_guid) {
1303                 goto failed;
1304         }
1305
1306         *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1307
1308         /* cache the domain_sid in the ldb */
1309         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1310                 goto failed;
1311         }
1312
1313         talloc_steal(ldb, ntds_guid);
1314         talloc_free(tmp_ctx);
1315
1316         return ntds_guid;
1317
1318 failed:
1319         DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1320         talloc_free(tmp_ctx);
1321         return NULL;
1322 }
1323
1324 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1325 {
1326         TALLOC_CTX *tmp_ctx;
1327         struct GUID *ntds_guid_new;
1328         struct GUID *ntds_guid_old;
1329         
1330         /* see if we have a cached copy */
1331         ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1332
1333         tmp_ctx = talloc_new(ldb);
1334         if (tmp_ctx == NULL) {
1335                 goto failed;
1336         }
1337
1338         ntds_guid_new = talloc(tmp_ctx, struct GUID);
1339         if (!ntds_guid_new) {
1340                 goto failed;
1341         }
1342
1343         *ntds_guid_new = *ntds_guid_in;
1344
1345         /* cache the domain_sid in the ldb */
1346         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1347                 goto failed;
1348         }
1349
1350         talloc_steal(ldb, ntds_guid_new);
1351         talloc_free(tmp_ctx);
1352         talloc_free(ntds_guid_old);
1353
1354         return true;
1355
1356 failed:
1357         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1358         talloc_free(tmp_ctx);
1359         return false;
1360 }
1361
1362 /*
1363   work out the server dn for the current open ldb
1364 */
1365 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1366 {
1367         return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1368 }
1369
1370 /*
1371   work out the server dn for the current open ldb
1372 */
1373 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1374 {
1375         struct ldb_dn *server_dn;
1376         struct ldb_dn *server_site_dn;
1377
1378         server_dn = samdb_server_dn(ldb, mem_ctx);
1379         if (!server_dn) return NULL;
1380
1381         server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1382
1383         talloc_free(server_dn);
1384         return server_site_dn;
1385 }
1386
1387 /*
1388   work out if we are the PDC for the domain of the current open ldb
1389 */
1390 bool samdb_is_pdc(struct ldb_context *ldb)
1391 {
1392         const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1393         int ret;
1394         struct ldb_result *dom_res;
1395         TALLOC_CTX *tmp_ctx;
1396         bool is_pdc;
1397         struct ldb_dn *pdc;
1398
1399         tmp_ctx = talloc_new(ldb);
1400         if (tmp_ctx == NULL) {
1401                 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1402                 return false;
1403         }
1404
1405         ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1406         if (ret) {
1407                 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n", 
1408                          ldb_dn_get_linearized(ldb_get_default_basedn(ldb)), 
1409                          ldb_errstring(ldb)));
1410                 goto failed;
1411         }
1412         if (dom_res->count != 1) {
1413                 goto failed;
1414         }
1415
1416         pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1417
1418         if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1419                 is_pdc = true;
1420         } else {
1421                 is_pdc = false;
1422         }
1423
1424         talloc_free(tmp_ctx);
1425
1426         return is_pdc;
1427
1428 failed:
1429         DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1430         talloc_free(tmp_ctx);
1431         return false;
1432 }
1433
1434 /*
1435   work out if we are a Global Catalog server for the domain of the current open ldb
1436 */
1437 bool samdb_is_gc(struct ldb_context *ldb)
1438 {
1439         const char *attrs[] = { "options", NULL };
1440         int ret, options;
1441         struct ldb_result *res;
1442         TALLOC_CTX *tmp_ctx;
1443
1444         tmp_ctx = talloc_new(ldb);
1445         if (tmp_ctx == NULL) {
1446                 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1447                 return false;
1448         }
1449
1450         /* Query cn=ntds settings,.... */
1451         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1452         if (ret) {
1453                 talloc_free(tmp_ctx);
1454                 return false;
1455         }
1456         if (res->count != 1) {
1457                 talloc_free(tmp_ctx);
1458                 return false;
1459         }
1460
1461         options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1462         talloc_free(tmp_ctx);
1463
1464         /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1465         if (options & 0x000000001) {
1466                 return true;
1467         }
1468         return false;
1469 }
1470
1471 /* Find a domain object in the parents of a particular DN.  */
1472 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1473                                    struct ldb_dn **parent_dn, const char **errstring)
1474 {
1475         TALLOC_CTX *local_ctx;
1476         struct ldb_dn *sdn = dn;
1477         struct ldb_result *res = NULL;
1478         int ret = 0;
1479         const char *attrs[] = { NULL };
1480
1481         local_ctx = talloc_new(mem_ctx);
1482         if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1483         
1484         while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1485                 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1486                                  "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");
1487                 if (ret == LDB_SUCCESS) {
1488                         if (res->count == 1) {
1489                                 break;
1490                         }
1491                 } else {
1492                         break;
1493                 }
1494         }
1495
1496         if (ret != LDB_SUCCESS) {
1497                 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1498                                              ldb_dn_get_linearized(dn),
1499                                              ldb_dn_get_linearized(sdn),
1500                                              ldb_errstring(ldb));
1501                 talloc_free(local_ctx);
1502                 return ret;
1503         }
1504         if (res->count != 1) {
1505                 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1506                                              ldb_dn_get_linearized(dn));
1507                 talloc_free(local_ctx);
1508                 return LDB_ERR_CONSTRAINT_VIOLATION;
1509         }
1510
1511         *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1512         talloc_free(local_ctx);
1513         return ret;
1514 }
1515
1516 /*
1517   check that a password is sufficiently complex
1518 */
1519 static bool samdb_password_complexity_ok(const char *pass)
1520 {
1521         return check_password_quality(pass);
1522 }
1523
1524
1525
1526 /*
1527   set the user password using plaintext, obeying any user or domain
1528   password restrictions
1529
1530   note that this function doesn't actually store the result in the
1531   database, it just fills in the "mod" structure with ldb modify
1532   elements to setup the correct change when samdb_replace() is
1533   called. This allows the caller to combine the change with other
1534   changes (as is needed by some of the set user info levels)
1535
1536   The caller should probably have a transaction wrapping this
1537 */
1538 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1539                             struct ldb_dn *user_dn,
1540                             struct ldb_dn *domain_dn,
1541                             struct ldb_message *mod,
1542                             const DATA_BLOB *new_password,
1543                             struct samr_Password *lmNewHash, 
1544                             struct samr_Password *ntNewHash,
1545                             bool user_change,
1546                             enum samr_RejectReason *reject_reason,
1547                             struct samr_DomInfo1 **_dominfo)
1548 {
1549         const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory", 
1550                                             "ntPwdHistory", 
1551                                             "dBCSPwd", "unicodePwd", 
1552                                             "objectSid", 
1553                                             "pwdLastSet", NULL };
1554         const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength", 
1555                                               "maxPwdAge", "minPwdAge", 
1556                                               "minPwdLength", NULL };
1557         NTTIME pwdLastSet;
1558         int64_t minPwdAge;
1559         uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1560         uint_t userAccountControl;
1561         struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1562         struct samr_Password local_lmNewHash, local_ntNewHash;
1563         int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1564         struct dom_sid *domain_sid;
1565         struct ldb_message **res;
1566         bool restrictions;
1567         int count;
1568         time_t now = time(NULL);
1569         NTTIME now_nt;
1570         int i;
1571
1572         /* we need to know the time to compute password age */
1573         unix_to_nt_time(&now_nt, now);
1574
1575         /* pull all the user parameters */
1576         count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1577         if (count != 1) {
1578                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1579         }
1580         userAccountControl = samdb_result_uint(res[0],   "userAccountControl", 0);
1581         sambaLMPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1582                                                  "lmPwdHistory", &sambaLMPwdHistory);
1583         sambaNTPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1584                                                  "ntPwdHistory", &sambaNTPwdHistory);
1585         lmPwdHash =          samdb_result_hash(mem_ctx, res[0],   "dBCSPwd");
1586         ntPwdHash =          samdb_result_hash(mem_ctx, res[0],   "unicodePwd");
1587         pwdLastSet =         samdb_result_uint64(res[0], "pwdLastSet", 0);
1588
1589         /* Only non-trust accounts have restrictions (possibly this
1590          * test is the wrong way around, but I like to be restrictive
1591          * if possible */
1592         restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1593                                                |UF_WORKSTATION_TRUST_ACCOUNT
1594                                                |UF_SERVER_TRUST_ACCOUNT)); 
1595
1596         if (domain_dn) {
1597                 /* pull the domain parameters */
1598                 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1599                 if (count != 1) {
1600                         DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n", 
1601                                   ldb_dn_get_linearized(domain_dn),
1602                                   ldb_dn_get_linearized(user_dn)));
1603                         return NT_STATUS_NO_SUCH_DOMAIN;
1604                 }
1605         } else {
1606                 /* work out the domain sid, and pull the domain from there */
1607                 domain_sid =         samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1608                 if (domain_sid == NULL) {
1609                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1610                 }
1611
1612                 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs, 
1613                                      "(objectSid=%s)", 
1614                                      ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1615                 if (count != 1) {
1616                         DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n", 
1617                                   dom_sid_string(mem_ctx, domain_sid),
1618                                   ldb_dn_get_linearized(user_dn)));
1619                         return NT_STATUS_NO_SUCH_DOMAIN;
1620                 }
1621         }
1622
1623         pwdProperties =    samdb_result_uint(res[0],   "pwdProperties", 0);
1624         pwdHistoryLength = samdb_result_uint(res[0],   "pwdHistoryLength", 0);
1625         minPwdLength =     samdb_result_uint(res[0],   "minPwdLength", 0);
1626         minPwdAge =        samdb_result_int64(res[0],  "minPwdAge", 0);
1627
1628         if (_dominfo) {
1629                 struct samr_DomInfo1 *dominfo;
1630                 /* on failure we need to fill in the reject reasons */
1631                 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1632                 if (dominfo == NULL) {
1633                         return NT_STATUS_NO_MEMORY;
1634                 }
1635                 dominfo->min_password_length     = minPwdLength;
1636                 dominfo->password_properties     = pwdProperties;
1637                 dominfo->password_history_length = pwdHistoryLength;
1638                 dominfo->max_password_age        = minPwdAge;
1639                 dominfo->min_password_age        = minPwdAge;
1640                 *_dominfo = dominfo;
1641         }
1642
1643         if (restrictions && new_password) {
1644                 char *new_pass;
1645                 
1646                 /* check the various password restrictions */
1647                 if (restrictions && minPwdLength > utf16_len_n(new_password->data, new_password->length) / 2) {
1648                         if (reject_reason) {
1649                                 *reject_reason = SAMR_REJECT_TOO_SHORT;
1650                         }
1651                         return NT_STATUS_PASSWORD_RESTRICTION;
1652                 }
1653
1654                 /* Create the NT hash */
1655                 mdfour(local_ntNewHash.hash, new_password->data, new_password->length);
1656                 
1657                 ntNewHash = &local_ntNewHash;
1658
1659                 /* Only check complexity if we can convert it at all.  Assuming unconvertable passwords are 'strong' */
1660                 if (convert_string_talloc(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")), 
1661                                           CH_UTF16, CH_UNIX, 
1662                                           new_password->data, new_password->length, 
1663                                           (void **)&new_pass) != -1) {
1664                         
1665                         
1666                         /* possibly check password complexity */
1667                         if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1668                             !samdb_password_complexity_ok(new_pass)) {
1669                                 if (reject_reason) {
1670                                         *reject_reason = SAMR_REJECT_COMPLEXITY;
1671                                 }
1672                                 return NT_STATUS_PASSWORD_RESTRICTION;
1673                         }
1674                         
1675                         /* compute the new lm hashes (for checking history - case insenitivly!) */
1676                         if (E_deshash(new_pass, local_lmNewHash.hash)) {
1677                                 lmNewHash = &local_lmNewHash;
1678                         }
1679                         
1680                 }
1681         }
1682
1683         if (restrictions && user_change) {
1684                 /* are all password changes disallowed? */
1685                 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1686                         if (reject_reason) {
1687                                 *reject_reason = SAMR_REJECT_OTHER;
1688                         }
1689                         return NT_STATUS_PASSWORD_RESTRICTION;
1690                 }
1691                 
1692                 /* can this user change password? */
1693                 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1694                         if (reject_reason) {
1695                                 *reject_reason = SAMR_REJECT_OTHER;
1696                         }
1697                         return NT_STATUS_PASSWORD_RESTRICTION;
1698                 }
1699                 
1700                 /* yes, this is a minus. The ages are in negative 100nsec units! */
1701                 if (pwdLastSet - minPwdAge > now_nt) {
1702                         if (reject_reason) {
1703                                 *reject_reason = SAMR_REJECT_OTHER;
1704                         }
1705                         return NT_STATUS_PASSWORD_RESTRICTION;
1706                 }
1707
1708                 /* check the immediately past password */
1709                 if (pwdHistoryLength > 0) {
1710                         if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1711                                 if (reject_reason) {
1712                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1713                                 }
1714                                 return NT_STATUS_PASSWORD_RESTRICTION;
1715                         }
1716                         if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1717                                 if (reject_reason) {
1718                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1719                                 }
1720                                 return NT_STATUS_PASSWORD_RESTRICTION;
1721                         }
1722                 }
1723                 
1724                 /* check the password history */
1725                 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1726                 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1727                 
1728                 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1729                         if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1730                                 if (reject_reason) {
1731                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1732                                 }
1733                                 return NT_STATUS_PASSWORD_RESTRICTION;
1734                         }
1735                 }
1736                 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1737                         if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1738                                 if (reject_reason) {
1739                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1740                                 }
1741                                 return NT_STATUS_PASSWORD_RESTRICTION;
1742                         }
1743                 }
1744         }
1745
1746 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1747
1748         /* the password is acceptable. Start forming the new fields */
1749         if (new_password) {
1750                 /* if we know the cleartext UTF16 password, then set it.
1751                  * Modules in ldb will set all the appropriate
1752                  * hashes */
1753                 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
1754         } else {
1755                 /* We don't have the cleartext, so delete the old one
1756                  * and set what we have of the hashes */
1757                 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword"));
1758
1759                 if (lmNewHash) {
1760                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1761                 } else {
1762                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1763                 }
1764                 
1765                 if (ntNewHash) {
1766                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1767                 } else {
1768                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1769                 }
1770         }
1771
1772         return NT_STATUS_OK;
1773 }
1774
1775
1776 /*
1777   set the user password using plaintext, obeying any user or domain
1778   password restrictions
1779
1780   This wrapper function takes a SID as input, rather than a user DN,
1781   and actually performs the password change
1782
1783 */
1784 NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1785                                 const struct dom_sid *user_sid,
1786                                 const DATA_BLOB *new_pass,
1787                                 struct samr_Password *lmNewHash, 
1788                                 struct samr_Password *ntNewHash,
1789                                 bool user_change,
1790                                 enum samr_RejectReason *reject_reason,
1791                                 struct samr_DomInfo1 **_dominfo) 
1792 {
1793         NTSTATUS nt_status;
1794         struct ldb_dn *user_dn;
1795         struct ldb_message *msg;
1796         int ret;
1797
1798         ret = ldb_transaction_start(ctx);
1799         if (ret) {
1800                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1801                 return NT_STATUS_TRANSACTION_ABORTED;
1802         }
1803
1804         user_dn = samdb_search_dn(ctx, mem_ctx, NULL, 
1805                                   "(&(objectSid=%s)(objectClass=user))", 
1806                                   ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1807         if (!user_dn) {
1808                 ldb_transaction_cancel(ctx);
1809                 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1810                           dom_sid_string(mem_ctx, user_sid)));
1811                 return NT_STATUS_NO_SUCH_USER;
1812         }
1813
1814         msg = ldb_msg_new(mem_ctx);
1815         if (msg == NULL) {
1816                 ldb_transaction_cancel(ctx);
1817                 return NT_STATUS_NO_MEMORY;
1818         }
1819
1820         msg->dn = ldb_dn_copy(msg, user_dn);
1821         if (!msg->dn) {
1822                 ldb_transaction_cancel(ctx);
1823                 return NT_STATUS_NO_MEMORY;
1824         }
1825
1826         nt_status = samdb_set_password(ctx, mem_ctx,
1827                                        user_dn, NULL,
1828                                        msg, new_pass, 
1829                                        lmNewHash, ntNewHash,
1830                                        user_change, /* This is a password set, not change */
1831                                        reject_reason, _dominfo);
1832         if (!NT_STATUS_IS_OK(nt_status)) {
1833                 ldb_transaction_cancel(ctx);
1834                 return nt_status;
1835         }
1836         
1837         /* modify the samdb record */
1838         ret = samdb_replace(ctx, mem_ctx, msg);
1839         if (ret != 0) {
1840                 ldb_transaction_cancel(ctx);
1841                 return NT_STATUS_ACCESS_DENIED;
1842         }
1843
1844         ret = ldb_transaction_commit(ctx);
1845         if (ret != 0) {
1846                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1847                          ldb_dn_get_linearized(msg->dn),
1848                          ldb_errstring(ctx)));
1849                 return NT_STATUS_TRANSACTION_ABORTED;
1850         }
1851         return NT_STATUS_OK;
1852 }
1853
1854
1855
1856 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
1857                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
1858 {
1859         struct ldb_message *msg;
1860         struct ldb_dn *basedn;
1861         const char *sidstr;
1862         int ret;
1863         
1864         sidstr = dom_sid_string(mem_ctx, sid);
1865         NT_STATUS_HAVE_NO_MEMORY(sidstr);
1866         
1867         /* We might have to create a ForeignSecurityPrincipal, even if this user
1868          * is in our own domain */
1869         
1870         msg = ldb_msg_new(mem_ctx);
1871         if (msg == NULL) {
1872                 return NT_STATUS_NO_MEMORY;
1873         }
1874         
1875         /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1876          * put the ForeignSecurityPrincipals? d_state->domain_dn does
1877          * not work, this is wrong for the Builtin domain, there's no
1878          * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
1879          */
1880         
1881         basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1882                                  "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1883         
1884         if (basedn == NULL) {
1885                 DEBUG(0, ("Failed to find DN for "
1886                           "ForeignSecurityPrincipal container\n"));
1887                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1888         }
1889         
1890         /* add core elements to the ldb_message for the alias */
1891         msg->dn = ldb_dn_copy(mem_ctx, basedn);
1892         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1893                 return NT_STATUS_NO_MEMORY;
1894         
1895         samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1896                              "objectClass",
1897                              "foreignSecurityPrincipal");
1898         
1899         /* create the alias */
1900         ret = ldb_add(sam_ctx, msg);
1901         if (ret != 0) {
1902                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1903                          "record %s: %s\n", 
1904                          ldb_dn_get_linearized(msg->dn),
1905                          ldb_errstring(sam_ctx)));
1906                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1907         }
1908         *ret_dn = msg->dn;
1909         return NT_STATUS_OK;
1910 }
1911
1912
1913 /*
1914   Find the DN of a domain, assuming it to be a dotted.dns name
1915 */
1916
1917 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) 
1918 {
1919         int i;
1920         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1921         const char *binary_encoded;
1922         const char **split_realm;
1923         struct ldb_dn *dn;
1924         
1925         if (!tmp_ctx) {
1926                 return NULL;
1927         }
1928         
1929         split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
1930         if (!split_realm) {
1931                 talloc_free(tmp_ctx);
1932                 return NULL;
1933         }
1934         dn = ldb_dn_new(mem_ctx, ldb, NULL);
1935         for (i=0; split_realm[i]; i++) {
1936                 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1937                 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1938                         DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1939                                   binary_encoded, ldb_dn_get_linearized(dn)));
1940                         talloc_free(tmp_ctx);
1941                         return NULL;
1942                 }
1943         }
1944         if (!ldb_dn_validate(dn)) {
1945                 DEBUG(2, ("Failed to validated DN %s\n",
1946                           ldb_dn_get_linearized(dn)));
1947                 return NULL;
1948         }
1949         return dn;
1950 }
1951 /*
1952   Find the DN of a domain, be it the netbios or DNS name 
1953 */
1954
1955 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
1956                                   const char *domain_name) 
1957 {
1958         const char * const domain_ref_attrs[] = {
1959                 "ncName", NULL
1960         };
1961         const char * const domain_ref2_attrs[] = {
1962                 NULL
1963         };
1964         struct ldb_result *res_domain_ref;
1965         char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1966         /* find the domain's DN */
1967         int ret_domain = ldb_search(ldb, mem_ctx,
1968                                             &res_domain_ref, 
1969                                             samdb_partitions_dn(ldb, mem_ctx), 
1970                                             LDB_SCOPE_ONELEVEL, 
1971                                             domain_ref_attrs,
1972                                             "(&(nETBIOSName=%s)(objectclass=crossRef))", 
1973                                             escaped_domain);
1974         if (ret_domain != 0) {
1975                 return NULL;
1976         }
1977         
1978         if (res_domain_ref->count == 0) {
1979                 ret_domain = ldb_search(ldb, mem_ctx,
1980                                                 &res_domain_ref, 
1981                                                 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
1982                                                 LDB_SCOPE_BASE,
1983                                                 domain_ref2_attrs,
1984                                                 "(objectclass=domain)");
1985                 if (ret_domain != 0) {
1986                         return NULL;
1987                 }
1988         
1989                 if (res_domain_ref->count == 1) {
1990                         return res_domain_ref->msgs[0]->dn;
1991                 }
1992                 return NULL;
1993         }
1994         
1995         if (res_domain_ref->count > 1) {
1996                 DEBUG(0,("Found %d records matching domain [%s]\n", 
1997                          ret_domain, domain_name));
1998                 return NULL;
1999         }
2000         
2001         return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2002
2003 }