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