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