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