r17529: Simo doesn't like the use of the internal ldb_errstring in functions
[gd/samba-autobuild/.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                         char **errstring)
679 {
680         struct ldb_result *res;
681         struct ldb_message *t;
682         int ret, i, j;
683
684         *errstring = NULL;
685         
686         struct ldb_dn *basedn = ldb_dn_explode(ldb, "cn=Templates");
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, "objectGUID") == 0) {
710                         continue;
711                 }
712                 for (j = 0; j < el->num_values; j++) {
713                         if (strcasecmp(el->name, "objectClass") == 0) {
714                                 if (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
715                                     strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
716                                     strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
717                                     strcasecmp((char *)el->values[j].data, "foreignSecurityPrincipalTemplate") == 0 ||
718                                     strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 || 
719                                     strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 || 
720                                     strcasecmp((char *)el->values[j].data, "secretTemplate") == 0) {
721                                         continue;
722                                 }
723                                 ret = samdb_find_or_add_value(ldb, msg, el->name, 
724                                                               (char *)el->values[j].data);
725                                 if (ret) {
726                                         *errstring = talloc_asprintf(msg, "Adding objectClass %s failed.\n", el->values[j].data);
727                                         talloc_free(res);
728                                         return ret;
729                                 }
730                         } else {
731                                 ret = samdb_find_or_add_attribute(ldb, msg, el->name, 
732                                                                   (char *)el->values[j].data);
733                                 if (ret) {
734                                         *errstring = talloc_asprintf(msg, "Adding attribute %s failed.\n", el->name);
735                                         talloc_free(res);
736                                         return ret;
737                                 }
738                         }
739                 }
740         }
741
742         talloc_free(res);
743
744         return LDB_SUCCESS;
745 }
746
747
748 /*
749   add a string element to a message
750 */
751 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
752                          const char *attr_name, const char *str)
753 {
754         char *s = talloc_strdup(mem_ctx, str);
755         char *a = talloc_strdup(mem_ctx, attr_name);
756         if (s == NULL || a == NULL) {
757                 return LDB_ERR_OPERATIONS_ERROR;
758         }
759         return ldb_msg_add_string(msg, a, s);
760 }
761
762 /*
763   add a dom_sid element to a message
764 */
765 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
766                          const char *attr_name, struct dom_sid *sid)
767 {
768         struct ldb_val v;
769         NTSTATUS status;
770         status = ndr_push_struct_blob(&v, mem_ctx, sid, 
771                                       (ndr_push_flags_fn_t)ndr_push_dom_sid);
772         if (!NT_STATUS_IS_OK(status)) {
773                 return -1;
774         }
775         return ldb_msg_add_value(msg, attr_name, &v);
776 }
777
778
779 /*
780   add a delete element operation to a message
781 */
782 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
783                          const char *attr_name)
784 {
785         /* we use an empty replace rather than a delete, as it allows for 
786            samdb_replace() to be used everywhere */
787         return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE);
788 }
789
790 /*
791   add a add attribute value to a message
792 */
793 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
794                          const char *attr_name, const char *value)
795 {
796         struct ldb_message_element *el;
797         char *a, *v;
798         int ret;
799         a = talloc_strdup(mem_ctx, attr_name);
800         if (a == NULL)
801                 return -1;
802         v = talloc_strdup(mem_ctx, value);
803         if (v == NULL)
804                 return -1;
805         ret = ldb_msg_add_string(msg, a, v);
806         if (ret != 0)
807                 return ret;
808         el = ldb_msg_find_element(msg, a);
809         if (el == NULL)
810                 return -1;
811         el->flags = LDB_FLAG_MOD_ADD;
812         return 0;
813 }
814
815 /*
816   add a delete attribute value to a message
817 */
818 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
819                          const char *attr_name, const char *value)
820 {
821         struct ldb_message_element *el;
822         char *a, *v;
823         int ret;
824         a = talloc_strdup(mem_ctx, attr_name);
825         if (a == NULL)
826                 return -1;
827         v = talloc_strdup(mem_ctx, value);
828         if (v == NULL)
829                 return -1;
830         ret = ldb_msg_add_string(msg, a, v);
831         if (ret != 0)
832                 return ret;
833         el = ldb_msg_find_element(msg, a);
834         if (el == NULL)
835                 return -1;
836         el->flags = LDB_FLAG_MOD_DELETE;
837         return 0;
838 }
839
840 /*
841   add a int element to a message
842 */
843 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
844                        const char *attr_name, int v)
845 {
846         const char *s = talloc_asprintf(mem_ctx, "%d", v);
847         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
848 }
849
850 /*
851   add a uint_t element to a message
852 */
853 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
854                        const char *attr_name, uint_t v)
855 {
856         const char *s = talloc_asprintf(mem_ctx, "%u", v);
857         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
858 }
859
860 /*
861   add a (signed) int64_t element to a message
862 */
863 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
864                         const char *attr_name, int64_t v)
865 {
866         const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
867         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
868 }
869
870 /*
871   add a uint64_t element to a message
872 */
873 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
874                         const char *attr_name, uint64_t v)
875 {
876         const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
877         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
878 }
879
880 /*
881   add a samr_Password element to a message
882 */
883 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
884                        const char *attr_name, struct samr_Password *hash)
885 {
886         struct ldb_val val;
887         val.data = talloc_memdup(mem_ctx, hash->hash, 16);
888         if (!val.data) {
889                 return -1;
890         }
891         val.length = 16;
892         return ldb_msg_add_value(msg, attr_name, &val);
893 }
894
895 /*
896   add a samr_Password array to a message
897 */
898 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
899                          const char *attr_name, struct samr_Password *hashes, uint_t count)
900 {
901         struct ldb_val val;
902         int i;
903         val.data = talloc_array_size(mem_ctx, 16, count);
904         val.length = count*16;
905         if (!val.data) {
906                 return -1;
907         }
908         for (i=0;i<count;i++) {
909                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
910         }
911         return ldb_msg_add_value(msg, attr_name, &val);
912 }
913
914 /*
915   add a acct_flags element to a message
916 */
917 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
918                              const char *attr_name, uint32_t v)
919 {
920         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
921 }
922
923 /*
924   add a logon_hours element to a message
925 */
926 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
927                               const char *attr_name, struct samr_LogonHours *hours)
928 {
929         struct ldb_val val;
930         val.length = hours->units_per_week / 8;
931         val.data = hours->bits;
932         return ldb_msg_add_value(msg, attr_name, &val);
933 }
934
935 /*
936   add a general value element to a message
937 */
938 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
939                               const char *attr_name, const struct ldb_val *val)
940 {
941         return ldb_msg_add_value(msg, attr_name, val);
942 }
943
944 /*
945   sets a general value element to a message
946 */
947 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
948                         const char *attr_name, const struct ldb_val *val)
949 {
950         struct ldb_message_element *el;
951
952         el = ldb_msg_find_element(msg, attr_name);
953         if (el) {
954                 el->num_values = 0;
955         }
956         return ldb_msg_add_value(msg, attr_name, val);
957 }
958
959 /*
960   set a string element in a message
961 */
962 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
963                          const char *attr_name, const char *str)
964 {
965         struct ldb_message_element *el;
966
967         el = ldb_msg_find_element(msg, attr_name);
968         if (el) {
969                 el->num_values = 0;
970         }
971         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
972 }
973
974 /*
975   add a record
976 */
977 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
978 {
979         return ldb_add(sam_ldb, msg);
980 }
981
982 /*
983   delete a record
984 */
985 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, const struct ldb_dn *dn)
986 {
987         return ldb_delete(sam_ldb, dn);
988 }
989
990 /*
991   modify a record
992 */
993 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
994 {
995         return ldb_modify(sam_ldb, msg);
996 }
997
998 /*
999   replace elements in a record
1000 */
1001 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1002 {
1003         int i;
1004
1005         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1006         for (i=0;i<msg->num_elements;i++) {
1007                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1008         }
1009
1010         /* modify the samdb record */
1011         return samdb_modify(sam_ldb, mem_ctx, msg);
1012 }
1013
1014 /*
1015   return a default security descriptor
1016 */
1017 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1018 {
1019         struct security_descriptor *sd;
1020
1021         sd = security_descriptor_initialise(mem_ctx);
1022
1023         return sd;
1024 }
1025
1026 struct ldb_dn *samdb_base_dn(TALLOC_CTX *mem_ctx) 
1027 {
1028         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1029         int server_role = lp_server_role();
1030         const char **split_realm;
1031         struct ldb_dn *dn;
1032         
1033         if (!tmp_ctx) {
1034                 return NULL;
1035         }
1036
1037         if ((server_role == ROLE_DOMAIN_PDC)
1038             || (server_role == ROLE_DOMAIN_BDC)) {
1039                 int i;
1040                 split_realm = str_list_make(tmp_ctx, lp_realm(), ".");
1041                 if (!split_realm) {
1042                         talloc_free(tmp_ctx);
1043                         return NULL;
1044                 }
1045                 dn = NULL;
1046                 i = str_list_length(split_realm);
1047                 i--;
1048                 for (; i >= 0; i--) {
1049                         dn = ldb_dn_build_child(tmp_ctx, "dc", split_realm[i], dn);
1050                         if (!dn) {
1051                                 talloc_free(tmp_ctx);
1052                                 return NULL;
1053                         }
1054                 }
1055                 return dn;
1056         }
1057         return ldb_dn_string_compose(mem_ctx, NULL, "cn=%s", lp_netbios_name());
1058 }
1059
1060
1061 /*
1062   work out the domain sid for the current open ldb
1063 */
1064 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1065 {
1066         const char *attrs[] = { "rootDomainNamingContext", NULL };
1067         int ret;
1068         struct ldb_result *res = NULL;
1069         TALLOC_CTX *tmp_ctx;
1070         struct dom_sid *domain_sid;
1071         const char *basedn_s;
1072         struct ldb_dn *basedn;
1073
1074         /* see if we have a cached copy */
1075         domain_sid = ldb_get_opaque(ldb, "cache.domain_sid");
1076         if (domain_sid) {
1077                 return domain_sid;
1078         }
1079
1080         tmp_ctx = talloc_new(ldb);
1081         if (tmp_ctx == NULL) {
1082                 goto failed;
1083         }
1084
1085         basedn = ldb_dn_explode(tmp_ctx, "");
1086         if (basedn == NULL) {
1087                 goto failed;
1088         }
1089         
1090         /* find the basedn of the domain from the rootdse */
1091         ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, NULL, attrs, &res);
1092         talloc_steal(tmp_ctx, res);
1093         if (ret != LDB_SUCCESS || res->count != 1) {
1094                 goto failed;
1095         }
1096
1097         basedn_s = ldb_msg_find_attr_as_string(res->msgs[0], "rootDomainNamingContext", NULL);
1098         if (basedn_s == NULL) {
1099                 goto failed;
1100         }
1101
1102         basedn = ldb_dn_explode(tmp_ctx, basedn_s);
1103         if (basedn == NULL) {
1104                 goto failed;
1105         }
1106
1107         /* find the domain_sid */
1108         domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, basedn, 
1109                                           "objectSid", "objectClass=domainDNS");
1110         if (domain_sid == NULL) {
1111                 goto failed;
1112         }
1113
1114         /* cache the domain_sid in the ldb */
1115         if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1116                 goto failed;
1117         }
1118
1119         talloc_steal(ldb, domain_sid);
1120         talloc_free(tmp_ctx);
1121
1122         return domain_sid;
1123
1124 failed:
1125         DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1126         talloc_free(tmp_ctx);
1127         return NULL;
1128 }
1129
1130 /*
1131   check that a password is sufficiently complex
1132 */
1133 static BOOL samdb_password_complexity_ok(const char *pass)
1134 {
1135         return check_password_quality(pass);
1136 }
1137
1138
1139
1140 /*
1141   set the user password using plaintext, obeying any user or domain
1142   password restrictions
1143
1144   note that this function doesn't actually store the result in the
1145   database, it just fills in the "mod" structure with ldb modify
1146   elements to setup the correct change when samdb_replace() is
1147   called. This allows the caller to combine the change with other
1148   changes (as is needed by some of the set user info levels)
1149
1150   The caller should probably have a transaction wrapping this
1151 */
1152 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1153                             const struct ldb_dn *user_dn,
1154                             const struct ldb_dn *domain_dn,
1155                             struct ldb_message *mod,
1156                             const char *new_pass,
1157                             struct samr_Password *lmNewHash, 
1158                             struct samr_Password *ntNewHash,
1159                             BOOL user_change,
1160                             BOOL restrictions,
1161                             enum samr_RejectReason *reject_reason,
1162                             struct samr_DomInfo1 **_dominfo)
1163 {
1164         const char * const user_attrs[] = { "userAccountControl", "sambaLMPwdHistory", 
1165                                             "sambaNTPwdHistory", 
1166                                             "lmPwdHash", "ntPwdHash", 
1167                                             "objectSid", 
1168                                             "pwdLastSet", NULL };
1169         const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength", 
1170                                               "maxPwdAge", "minPwdAge", 
1171                                               "minPwdLength", NULL };
1172         NTTIME pwdLastSet;
1173         int64_t minPwdAge;
1174         uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1175         uint_t userAccountControl;
1176         struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1177         struct samr_Password local_lmNewHash, local_ntNewHash;
1178         int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1179         struct dom_sid *domain_sid;
1180         struct ldb_message **res;
1181         int count;
1182         time_t now = time(NULL);
1183         NTTIME now_nt;
1184         int i;
1185
1186         /* we need to know the time to compute password age */
1187         unix_to_nt_time(&now_nt, now);
1188
1189         /* pull all the user parameters */
1190         count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1191         if (count != 1) {
1192                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1193         }
1194         userAccountControl = samdb_result_uint(res[0],   "userAccountControl", 0);
1195         sambaLMPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1196                                                  "sambaLMPwdHistory", &sambaLMPwdHistory);
1197         sambaNTPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1198                                                  "sambaNTPwdHistory", &sambaNTPwdHistory);
1199         lmPwdHash =          samdb_result_hash(mem_ctx, res[0],   "lmPwdHash");
1200         ntPwdHash =          samdb_result_hash(mem_ctx, res[0],   "ntPwdHash");
1201         pwdLastSet =         samdb_result_uint64(res[0], "pwdLastSet", 0);
1202
1203         if (domain_dn) {
1204                 /* pull the domain parameters */
1205                 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1206                 if (count != 1) {
1207                         DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n", 
1208                                   ldb_dn_linearize(mem_ctx, domain_dn),
1209                                   ldb_dn_linearize(mem_ctx, user_dn)));
1210                         return NT_STATUS_NO_SUCH_DOMAIN;
1211                 }
1212         } else {
1213                 /* work out the domain sid, and pull the domain from there */
1214                 domain_sid =         samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1215                 if (domain_sid == NULL) {
1216                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1217                 }
1218
1219                 count = gendb_search(ctx, mem_ctx, samdb_base_dn(mem_ctx), &res, domain_attrs, 
1220                                      "(objectSid=%s)", 
1221                                      ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1222                 if (count != 1) {
1223                         DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n", 
1224                                   dom_sid_string(mem_ctx, domain_sid),
1225                                   ldb_dn_linearize(mem_ctx, user_dn)));
1226                         return NT_STATUS_NO_SUCH_DOMAIN;
1227                 }
1228         }
1229
1230         pwdProperties =    samdb_result_uint(res[0],   "pwdProperties", 0);
1231         pwdHistoryLength = samdb_result_uint(res[0],   "pwdHistoryLength", 0);
1232         minPwdLength =     samdb_result_uint(res[0],   "minPwdLength", 0);
1233         minPwdAge =        samdb_result_int64(res[0],  "minPwdAge", 0);
1234
1235         if (_dominfo) {
1236                 struct samr_DomInfo1 *dominfo;
1237                 /* on failure we need to fill in the reject reasons */
1238                 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1239                 if (dominfo == NULL) {
1240                         return NT_STATUS_NO_MEMORY;
1241                 }
1242                 dominfo->min_password_length     = minPwdLength;
1243                 dominfo->password_properties     = pwdProperties;
1244                 dominfo->password_history_length = pwdHistoryLength;
1245                 dominfo->max_password_age        = minPwdAge;
1246                 dominfo->min_password_age        = minPwdAge;
1247                 *_dominfo = dominfo;
1248         }
1249
1250         if (new_pass) {
1251                 /* check the various password restrictions */
1252                 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1253                         if (reject_reason) {
1254                                 *reject_reason = SAMR_REJECT_TOO_SHORT;
1255                         }
1256                         return NT_STATUS_PASSWORD_RESTRICTION;
1257                 }
1258                 
1259                 /* possibly check password complexity */
1260                 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1261                     !samdb_password_complexity_ok(new_pass)) {
1262                         if (reject_reason) {
1263                                 *reject_reason = SAMR_REJECT_COMPLEXITY;
1264                         }
1265                         return NT_STATUS_PASSWORD_RESTRICTION;
1266                 }
1267                 
1268                 /* compute the new nt and lm hashes */
1269                 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1270                         lmNewHash = &local_lmNewHash;
1271                 }
1272                 E_md4hash(new_pass, local_ntNewHash.hash);
1273                 ntNewHash = &local_ntNewHash;
1274         }
1275
1276         if (restrictions && user_change) {
1277                 /* are all password changes disallowed? */
1278                 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1279                         if (reject_reason) {
1280                                 *reject_reason = SAMR_REJECT_OTHER;
1281                         }
1282                         return NT_STATUS_PASSWORD_RESTRICTION;
1283                 }
1284                 
1285                 /* can this user change password? */
1286                 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1287                         if (reject_reason) {
1288                                 *reject_reason = SAMR_REJECT_OTHER;
1289                         }
1290                         return NT_STATUS_PASSWORD_RESTRICTION;
1291                 }
1292                 
1293                 /* yes, this is a minus. The ages are in negative 100nsec units! */
1294                 if (pwdLastSet - minPwdAge > now_nt) {
1295                         if (reject_reason) {
1296                                 *reject_reason = SAMR_REJECT_OTHER;
1297                         }
1298                         return NT_STATUS_PASSWORD_RESTRICTION;
1299                 }
1300
1301                 /* check the immediately past password */
1302                 if (pwdHistoryLength > 0) {
1303                         if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1304                                 if (reject_reason) {
1305                                         *reject_reason = SAMR_REJECT_COMPLEXITY;
1306                                 }
1307                                 return NT_STATUS_PASSWORD_RESTRICTION;
1308                         }
1309                         if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1310                                 if (reject_reason) {
1311                                         *reject_reason = SAMR_REJECT_COMPLEXITY;
1312                                 }
1313                                 return NT_STATUS_PASSWORD_RESTRICTION;
1314                         }
1315                 }
1316                 
1317                 /* check the password history */
1318                 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1319                 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1320                 
1321                 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1322                         if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1323                                 if (reject_reason) {
1324                                         *reject_reason = SAMR_REJECT_COMPLEXITY;
1325                                 }
1326                                 return NT_STATUS_PASSWORD_RESTRICTION;
1327                         }
1328                 }
1329                 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1330                         if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1331                                 if (reject_reason) {
1332                                         *reject_reason = SAMR_REJECT_COMPLEXITY;
1333                                 }
1334                                 return NT_STATUS_PASSWORD_RESTRICTION;
1335                         }
1336                 }
1337         }
1338
1339 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1340
1341         /* the password is acceptable. Start forming the new fields */
1342         if (new_pass) {
1343                 /* if we know the cleartext, then only set it.
1344                  * Modules in ldb will set all the appropriate
1345                  * hashes */
1346                 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod, 
1347                                                "sambaPassword", new_pass));
1348         } else {
1349                 /* We don't have the cleartext, so delete the old one
1350                  * and set what we have of the hashes */
1351                 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1352
1353                 if (lmNewHash) {
1354                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "lmPwdHash", lmNewHash));
1355                 } else {
1356                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHash"));
1357                 }
1358                 
1359                 if (ntNewHash) {
1360                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "ntPwdHash", ntNewHash));
1361                 } else {
1362                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHash"));
1363                 }
1364         }
1365
1366         return NT_STATUS_OK;
1367 }
1368
1369
1370 /*
1371   set the user password using plaintext, obeying any user or domain
1372   password restrictions
1373
1374   This wrapper function takes a SID as input, rather than a user DN,
1375   and actually performs the password change
1376
1377 */
1378 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1379                                 const struct dom_sid *user_sid,
1380                                 const char *new_pass,
1381                                 struct samr_Password *lmNewHash, 
1382                                 struct samr_Password *ntNewHash,
1383                                 BOOL user_change,
1384                                 BOOL restrictions,
1385                                 enum samr_RejectReason *reject_reason,
1386                                 struct samr_DomInfo1 **_dominfo) 
1387 {
1388         NTSTATUS nt_status;
1389         struct ldb_dn *user_dn;
1390         struct ldb_message *msg;
1391         int ret;
1392
1393         ret = ldb_transaction_start(ctx);
1394         if (ret) {
1395                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1396                 return NT_STATUS_TRANSACTION_ABORTED;
1397         }
1398
1399         user_dn = samdb_search_dn(ctx, mem_ctx, samdb_base_dn(mem_ctx), 
1400                                   "(&(objectSid=%s)(objectClass=user))", 
1401                                   ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1402         if (!user_dn) {
1403                 ldb_transaction_cancel(ctx);
1404                 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1405                           dom_sid_string(mem_ctx, user_sid)));
1406                 return NT_STATUS_NO_SUCH_USER;
1407         }
1408
1409         msg = ldb_msg_new(mem_ctx);
1410         if (msg == NULL) {
1411                 ldb_transaction_cancel(ctx);
1412                 return NT_STATUS_NO_MEMORY;
1413         }
1414
1415         msg->dn = ldb_dn_copy(msg, user_dn);
1416         if (!msg->dn) {
1417                 ldb_transaction_cancel(ctx);
1418                 return NT_STATUS_NO_MEMORY;
1419         }
1420
1421         nt_status = samdb_set_password(ctx, mem_ctx,
1422                                        user_dn, NULL,
1423                                        msg, new_pass, 
1424                                        lmNewHash, ntNewHash,
1425                                        user_change, /* This is a password set, not change */
1426                                        restrictions, /* run restriction tests */
1427                                        reject_reason, _dominfo);
1428         if (!NT_STATUS_IS_OK(nt_status)) {
1429                 ldb_transaction_cancel(ctx);
1430                 return nt_status;
1431         }
1432         
1433         /* modify the samdb record */
1434         ret = samdb_replace(ctx, mem_ctx, msg);
1435         if (ret != 0) {
1436                 ldb_transaction_cancel(ctx);
1437                 return NT_STATUS_ACCESS_DENIED;
1438         }
1439
1440         ret = ldb_transaction_commit(ctx);
1441         if (ret != 0) {
1442                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1443                          ldb_dn_linearize(mem_ctx, msg->dn),
1444                          ldb_errstring(ctx)));
1445                 return NT_STATUS_TRANSACTION_ABORTED;
1446         }
1447         return NT_STATUS_OK;
1448 }
1449
1450 /****************************************************************************
1451  Create the SID list for this user.
1452 ****************************************************************************/
1453 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx, 
1454                                struct dom_sid *user_sid,
1455                                struct dom_sid *group_sid, 
1456                                int n_groupSIDs,
1457                                struct dom_sid **groupSIDs, 
1458                                BOOL is_authenticated,
1459                                struct security_token **token)
1460 {
1461         struct security_token *ptoken;
1462         int i;
1463         NTSTATUS status;
1464
1465         ptoken = security_token_initialise(mem_ctx);
1466         NT_STATUS_HAVE_NO_MEMORY(ptoken);
1467
1468         ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1469         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1470
1471         ptoken->user_sid = talloc_reference(ptoken, user_sid);
1472         ptoken->group_sid = talloc_reference(ptoken, group_sid);
1473         ptoken->privilege_mask = 0;
1474
1475         ptoken->sids[0] = ptoken->user_sid;
1476         ptoken->sids[1] = ptoken->group_sid;
1477
1478         /*
1479          * Finally add the "standard" SIDs.
1480          * The only difference between guest and "anonymous"
1481          * is the addition of Authenticated_Users.
1482          */
1483         ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1484         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1485         ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1486         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1487         ptoken->num_sids = 4;
1488
1489         if (is_authenticated) {
1490                 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1491                 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1492                 ptoken->num_sids++;
1493         }
1494
1495         for (i = 0; i < n_groupSIDs; i++) {
1496                 size_t check_sid_idx;
1497                 for (check_sid_idx = 1; 
1498                      check_sid_idx < ptoken->num_sids; 
1499                      check_sid_idx++) {
1500                         if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1501                                 break;
1502                         }
1503                 }
1504
1505                 if (check_sid_idx == ptoken->num_sids) {
1506                         ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1507                 }
1508         }
1509
1510         /* setup the privilege mask for this token */
1511         status = samdb_privilege_setup(ptoken);
1512         if (!NT_STATUS_IS_OK(status)) {
1513                 talloc_free(ptoken);
1514                 return status;
1515         }
1516
1517         security_token_debug(10, ptoken);
1518
1519         *token = ptoken;
1520
1521         return NT_STATUS_OK;
1522 }
1523
1524
1525 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
1526                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
1527 {
1528         struct ldb_message *msg;
1529         struct ldb_dn *basedn;
1530         const char *sidstr;
1531         int ret;
1532         
1533         sidstr = dom_sid_string(mem_ctx, sid);
1534         NT_STATUS_HAVE_NO_MEMORY(sidstr);
1535         
1536         /* We might have to create a ForeignSecurityPrincipal, even if this user
1537          * is in our own domain */
1538         
1539         msg = ldb_msg_new(mem_ctx);
1540         if (msg == NULL) {
1541                 return NT_STATUS_NO_MEMORY;
1542         }
1543         
1544         /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1545          * put the ForeignSecurityPrincipals? d_state->domain_dn does
1546          * not work, this is wrong for the Builtin domain, there's no
1547          * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
1548          */
1549         
1550         basedn = samdb_search_dn(sam_ctx, mem_ctx, samdb_base_dn(mem_ctx),
1551                                  "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1552         
1553         if (basedn == NULL) {
1554                 DEBUG(0, ("Failed to find DN for "
1555                           "ForeignSecurityPrincipal container\n"));
1556                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1557         }
1558         
1559         /* add core elements to the ldb_message for the alias */
1560         msg->dn = ldb_dn_build_child(mem_ctx, "CN", sidstr, basedn);
1561         if (msg->dn == NULL)
1562                 return NT_STATUS_NO_MEMORY;
1563         
1564         samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1565                              "objectClass",
1566                              "foreignSecurityPrincipal");
1567         
1568         /* create the alias */
1569         ret = samdb_add(sam_ctx, mem_ctx, msg);
1570         if (ret != 0) {
1571                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1572                          "record %s: %s\n", 
1573                          ldb_dn_linearize(mem_ctx, msg->dn),
1574                          ldb_errstring(sam_ctx)));
1575                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1576         }
1577         *ret_dn = msg->dn;
1578         return NT_STATUS_OK;
1579 }