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