r19464: Reject passwords that cannot be converted into UCS2.
[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 "dsdb/common/flags.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 const struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx) 
1028 {
1029         return ldb_get_default_basedn(sam_ctx);
1030 }
1031
1032
1033 const struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx,
1034                                    TALLOC_CTX *mem_ctx)
1035 {
1036         return ldb_dn_string_compose(mem_ctx, samdb_base_dn(sam_ctx), 
1037                                      "CN=Partitions,CN=Configuration");
1038 }
1039
1040
1041 /*
1042   work out the domain sid for the current open ldb
1043 */
1044 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1045 {
1046         const char *attrs[] = { "rootDomainNamingContext", NULL };
1047         int ret;
1048         struct ldb_result *res = NULL;
1049         TALLOC_CTX *tmp_ctx;
1050         struct dom_sid *domain_sid;
1051         const char *basedn_s;
1052         struct ldb_dn *basedn;
1053
1054         /* see if we have a cached copy */
1055         domain_sid = ldb_get_opaque(ldb, "cache.domain_sid");
1056         if (domain_sid) {
1057                 return domain_sid;
1058         }
1059
1060         tmp_ctx = talloc_new(ldb);
1061         if (tmp_ctx == NULL) {
1062                 goto failed;
1063         }
1064
1065         basedn = ldb_dn_explode(tmp_ctx, "");
1066         if (basedn == NULL) {
1067                 goto failed;
1068         }
1069         
1070         /* find the basedn of the domain from the rootdse */
1071         ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, NULL, attrs, &res);
1072         talloc_steal(tmp_ctx, res);
1073         if (ret != LDB_SUCCESS || res->count != 1) {
1074                 goto failed;
1075         }
1076
1077         basedn_s = ldb_msg_find_attr_as_string(res->msgs[0], "rootDomainNamingContext", NULL);
1078         if (basedn_s == NULL) {
1079                 goto failed;
1080         }
1081
1082         basedn = ldb_dn_explode(tmp_ctx, basedn_s);
1083         if (basedn == NULL) {
1084                 goto failed;
1085         }
1086
1087         /* find the domain_sid */
1088         domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, basedn, 
1089                                           "objectSid", "objectClass=domainDNS");
1090         if (domain_sid == NULL) {
1091                 goto failed;
1092         }
1093
1094         /* cache the domain_sid in the ldb */
1095         if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1096                 goto failed;
1097         }
1098
1099         talloc_steal(ldb, domain_sid);
1100         talloc_free(tmp_ctx);
1101
1102         return domain_sid;
1103
1104 failed:
1105         DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1106         talloc_free(tmp_ctx);
1107         return NULL;
1108 }
1109
1110 /*
1111   check that a password is sufficiently complex
1112 */
1113 static BOOL samdb_password_complexity_ok(const char *pass)
1114 {
1115         return check_password_quality(pass);
1116 }
1117
1118
1119
1120 /*
1121   set the user password using plaintext, obeying any user or domain
1122   password restrictions
1123
1124   note that this function doesn't actually store the result in the
1125   database, it just fills in the "mod" structure with ldb modify
1126   elements to setup the correct change when samdb_replace() is
1127   called. This allows the caller to combine the change with other
1128   changes (as is needed by some of the set user info levels)
1129
1130   The caller should probably have a transaction wrapping this
1131 */
1132 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1133                             const struct ldb_dn *user_dn,
1134                             const struct ldb_dn *domain_dn,
1135                             struct ldb_message *mod,
1136                             const char *new_pass,
1137                             struct samr_Password *lmNewHash, 
1138                             struct samr_Password *ntNewHash,
1139                             BOOL user_change,
1140                             BOOL restrictions,
1141                             enum samr_RejectReason *reject_reason,
1142                             struct samr_DomInfo1 **_dominfo)
1143 {
1144         const char * const user_attrs[] = { "userAccountControl", "sambaLMPwdHistory", 
1145                                             "sambaNTPwdHistory", 
1146                                             "lmPwdHash", "ntPwdHash", 
1147                                             "objectSid", 
1148                                             "pwdLastSet", NULL };
1149         const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength", 
1150                                               "maxPwdAge", "minPwdAge", 
1151                                               "minPwdLength", NULL };
1152         NTTIME pwdLastSet;
1153         int64_t minPwdAge;
1154         uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1155         uint_t userAccountControl;
1156         struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1157         struct samr_Password local_lmNewHash, local_ntNewHash;
1158         int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1159         struct dom_sid *domain_sid;
1160         struct ldb_message **res;
1161         int count;
1162         time_t now = time(NULL);
1163         NTTIME now_nt;
1164         int i;
1165
1166         /* we need to know the time to compute password age */
1167         unix_to_nt_time(&now_nt, now);
1168
1169         /* pull all the user parameters */
1170         count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1171         if (count != 1) {
1172                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1173         }
1174         userAccountControl = samdb_result_uint(res[0],   "userAccountControl", 0);
1175         sambaLMPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1176                                                  "sambaLMPwdHistory", &sambaLMPwdHistory);
1177         sambaNTPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1178                                                  "sambaNTPwdHistory", &sambaNTPwdHistory);
1179         lmPwdHash =          samdb_result_hash(mem_ctx, res[0],   "lmPwdHash");
1180         ntPwdHash =          samdb_result_hash(mem_ctx, res[0],   "ntPwdHash");
1181         pwdLastSet =         samdb_result_uint64(res[0], "pwdLastSet", 0);
1182
1183         if (domain_dn) {
1184                 /* pull the domain parameters */
1185                 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1186                 if (count != 1) {
1187                         DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n", 
1188                                   ldb_dn_linearize(mem_ctx, domain_dn),
1189                                   ldb_dn_linearize(mem_ctx, user_dn)));
1190                         return NT_STATUS_NO_SUCH_DOMAIN;
1191                 }
1192         } else {
1193                 /* work out the domain sid, and pull the domain from there */
1194                 domain_sid =         samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1195                 if (domain_sid == NULL) {
1196                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1197                 }
1198
1199                 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs, 
1200                                      "(objectSid=%s)", 
1201                                      ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1202                 if (count != 1) {
1203                         DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n", 
1204                                   dom_sid_string(mem_ctx, domain_sid),
1205                                   ldb_dn_linearize(mem_ctx, user_dn)));
1206                         return NT_STATUS_NO_SUCH_DOMAIN;
1207                 }
1208         }
1209
1210         pwdProperties =    samdb_result_uint(res[0],   "pwdProperties", 0);
1211         pwdHistoryLength = samdb_result_uint(res[0],   "pwdHistoryLength", 0);
1212         minPwdLength =     samdb_result_uint(res[0],   "minPwdLength", 0);
1213         minPwdAge =        samdb_result_int64(res[0],  "minPwdAge", 0);
1214
1215         if (_dominfo) {
1216                 struct samr_DomInfo1 *dominfo;
1217                 /* on failure we need to fill in the reject reasons */
1218                 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1219                 if (dominfo == NULL) {
1220                         return NT_STATUS_NO_MEMORY;
1221                 }
1222                 dominfo->min_password_length     = minPwdLength;
1223                 dominfo->password_properties     = pwdProperties;
1224                 dominfo->password_history_length = pwdHistoryLength;
1225                 dominfo->max_password_age        = minPwdAge;
1226                 dominfo->min_password_age        = minPwdAge;
1227                 *_dominfo = dominfo;
1228         }
1229
1230         if (new_pass) {
1231                 /* check the various password restrictions */
1232                 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1233                         if (reject_reason) {
1234                                 *reject_reason = SAMR_REJECT_TOO_SHORT;
1235                         }
1236                         return NT_STATUS_PASSWORD_RESTRICTION;
1237                 }
1238                 
1239                 /* possibly check password complexity */
1240                 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1241                     !samdb_password_complexity_ok(new_pass)) {
1242                         if (reject_reason) {
1243                                 *reject_reason = SAMR_REJECT_COMPLEXITY;
1244                         }
1245                         return NT_STATUS_PASSWORD_RESTRICTION;
1246                 }
1247                 
1248                 /* compute the new nt and lm hashes */
1249                 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1250                         lmNewHash = &local_lmNewHash;
1251                 }
1252                 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1253                         /* If we can't convert this password to UCS2, then we should not accept it */
1254                         if (reject_reason) {
1255                                 *reject_reason = SAMR_REJECT_OTHER;
1256                         }
1257                         return NT_STATUS_PASSWORD_RESTRICTION;
1258                 }
1259                 ntNewHash = &local_ntNewHash;
1260         }
1261
1262         if (restrictions && user_change) {
1263                 /* are all password changes disallowed? */
1264                 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1265                         if (reject_reason) {
1266                                 *reject_reason = SAMR_REJECT_OTHER;
1267                         }
1268                         return NT_STATUS_PASSWORD_RESTRICTION;
1269                 }
1270                 
1271                 /* can this user change password? */
1272                 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1273                         if (reject_reason) {
1274                                 *reject_reason = SAMR_REJECT_OTHER;
1275                         }
1276                         return NT_STATUS_PASSWORD_RESTRICTION;
1277                 }
1278                 
1279                 /* yes, this is a minus. The ages are in negative 100nsec units! */
1280                 if (pwdLastSet - minPwdAge > now_nt) {
1281                         if (reject_reason) {
1282                                 *reject_reason = SAMR_REJECT_OTHER;
1283                         }
1284                         return NT_STATUS_PASSWORD_RESTRICTION;
1285                 }
1286
1287                 /* check the immediately past password */
1288                 if (pwdHistoryLength > 0) {
1289                         if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1290                                 if (reject_reason) {
1291                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1292                                 }
1293                                 return NT_STATUS_PASSWORD_RESTRICTION;
1294                         }
1295                         if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1296                                 if (reject_reason) {
1297                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1298                                 }
1299                                 return NT_STATUS_PASSWORD_RESTRICTION;
1300                         }
1301                 }
1302                 
1303                 /* check the password history */
1304                 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1305                 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1306                 
1307                 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1308                         if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1309                                 if (reject_reason) {
1310                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1311                                 }
1312                                 return NT_STATUS_PASSWORD_RESTRICTION;
1313                         }
1314                 }
1315                 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1316                         if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1317                                 if (reject_reason) {
1318                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1319                                 }
1320                                 return NT_STATUS_PASSWORD_RESTRICTION;
1321                         }
1322                 }
1323         }
1324
1325 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1326
1327         /* the password is acceptable. Start forming the new fields */
1328         if (new_pass) {
1329                 /* if we know the cleartext, then only set it.
1330                  * Modules in ldb will set all the appropriate
1331                  * hashes */
1332                 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod, 
1333                                                "sambaPassword", new_pass));
1334         } else {
1335                 /* We don't have the cleartext, so delete the old one
1336                  * and set what we have of the hashes */
1337                 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1338
1339                 if (lmNewHash) {
1340                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "lmPwdHash", lmNewHash));
1341                 } else {
1342                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHash"));
1343                 }
1344                 
1345                 if (ntNewHash) {
1346                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "ntPwdHash", ntNewHash));
1347                 } else {
1348                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHash"));
1349                 }
1350         }
1351
1352         return NT_STATUS_OK;
1353 }
1354
1355
1356 /*
1357   set the user password using plaintext, obeying any user or domain
1358   password restrictions
1359
1360   This wrapper function takes a SID as input, rather than a user DN,
1361   and actually performs the password change
1362
1363 */
1364 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1365                                 const struct dom_sid *user_sid,
1366                                 const char *new_pass,
1367                                 struct samr_Password *lmNewHash, 
1368                                 struct samr_Password *ntNewHash,
1369                                 BOOL user_change,
1370                                 BOOL restrictions,
1371                                 enum samr_RejectReason *reject_reason,
1372                                 struct samr_DomInfo1 **_dominfo) 
1373 {
1374         NTSTATUS nt_status;
1375         struct ldb_dn *user_dn;
1376         struct ldb_message *msg;
1377         int ret;
1378
1379         ret = ldb_transaction_start(ctx);
1380         if (ret) {
1381                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1382                 return NT_STATUS_TRANSACTION_ABORTED;
1383         }
1384
1385         user_dn = samdb_search_dn(ctx, mem_ctx, NULL, 
1386                                   "(&(objectSid=%s)(objectClass=user))", 
1387                                   ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1388         if (!user_dn) {
1389                 ldb_transaction_cancel(ctx);
1390                 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1391                           dom_sid_string(mem_ctx, user_sid)));
1392                 return NT_STATUS_NO_SUCH_USER;
1393         }
1394
1395         msg = ldb_msg_new(mem_ctx);
1396         if (msg == NULL) {
1397                 ldb_transaction_cancel(ctx);
1398                 return NT_STATUS_NO_MEMORY;
1399         }
1400
1401         msg->dn = ldb_dn_copy(msg, user_dn);
1402         if (!msg->dn) {
1403                 ldb_transaction_cancel(ctx);
1404                 return NT_STATUS_NO_MEMORY;
1405         }
1406
1407         nt_status = samdb_set_password(ctx, mem_ctx,
1408                                        user_dn, NULL,
1409                                        msg, new_pass, 
1410                                        lmNewHash, ntNewHash,
1411                                        user_change, /* This is a password set, not change */
1412                                        restrictions, /* run restriction tests */
1413                                        reject_reason, _dominfo);
1414         if (!NT_STATUS_IS_OK(nt_status)) {
1415                 ldb_transaction_cancel(ctx);
1416                 return nt_status;
1417         }
1418         
1419         /* modify the samdb record */
1420         ret = samdb_replace(ctx, mem_ctx, msg);
1421         if (ret != 0) {
1422                 ldb_transaction_cancel(ctx);
1423                 return NT_STATUS_ACCESS_DENIED;
1424         }
1425
1426         ret = ldb_transaction_commit(ctx);
1427         if (ret != 0) {
1428                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1429                          ldb_dn_linearize(mem_ctx, msg->dn),
1430                          ldb_errstring(ctx)));
1431                 return NT_STATUS_TRANSACTION_ABORTED;
1432         }
1433         return NT_STATUS_OK;
1434 }
1435
1436 /****************************************************************************
1437  Create the SID list for this user.
1438 ****************************************************************************/
1439 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx, 
1440                                struct dom_sid *user_sid,
1441                                struct dom_sid *group_sid, 
1442                                int n_groupSIDs,
1443                                struct dom_sid **groupSIDs, 
1444                                BOOL is_authenticated,
1445                                struct security_token **token)
1446 {
1447         struct security_token *ptoken;
1448         int i;
1449         NTSTATUS status;
1450
1451         ptoken = security_token_initialise(mem_ctx);
1452         NT_STATUS_HAVE_NO_MEMORY(ptoken);
1453
1454         ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1455         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1456
1457         ptoken->user_sid = talloc_reference(ptoken, user_sid);
1458         ptoken->group_sid = talloc_reference(ptoken, group_sid);
1459         ptoken->privilege_mask = 0;
1460
1461         ptoken->sids[0] = ptoken->user_sid;
1462         ptoken->sids[1] = ptoken->group_sid;
1463
1464         /*
1465          * Finally add the "standard" SIDs.
1466          * The only difference between guest and "anonymous"
1467          * is the addition of Authenticated_Users.
1468          */
1469         ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1470         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1471         ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1472         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1473         ptoken->num_sids = 4;
1474
1475         if (is_authenticated) {
1476                 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1477                 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1478                 ptoken->num_sids++;
1479         }
1480
1481         for (i = 0; i < n_groupSIDs; i++) {
1482                 size_t check_sid_idx;
1483                 for (check_sid_idx = 1; 
1484                      check_sid_idx < ptoken->num_sids; 
1485                      check_sid_idx++) {
1486                         if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1487                                 break;
1488                         }
1489                 }
1490
1491                 if (check_sid_idx == ptoken->num_sids) {
1492                         ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1493                 }
1494         }
1495
1496         /* setup the privilege mask for this token */
1497         status = samdb_privilege_setup(ptoken);
1498         if (!NT_STATUS_IS_OK(status)) {
1499                 talloc_free(ptoken);
1500                 return status;
1501         }
1502
1503         security_token_debug(10, ptoken);
1504
1505         *token = ptoken;
1506
1507         return NT_STATUS_OK;
1508 }
1509
1510
1511 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
1512                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
1513 {
1514         struct ldb_message *msg;
1515         struct ldb_dn *basedn;
1516         const char *sidstr;
1517         int ret;
1518         
1519         sidstr = dom_sid_string(mem_ctx, sid);
1520         NT_STATUS_HAVE_NO_MEMORY(sidstr);
1521         
1522         /* We might have to create a ForeignSecurityPrincipal, even if this user
1523          * is in our own domain */
1524         
1525         msg = ldb_msg_new(mem_ctx);
1526         if (msg == NULL) {
1527                 return NT_STATUS_NO_MEMORY;
1528         }
1529         
1530         /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1531          * put the ForeignSecurityPrincipals? d_state->domain_dn does
1532          * not work, this is wrong for the Builtin domain, there's no
1533          * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
1534          */
1535         
1536         basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1537                                  "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1538         
1539         if (basedn == NULL) {
1540                 DEBUG(0, ("Failed to find DN for "
1541                           "ForeignSecurityPrincipal container\n"));
1542                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1543         }
1544         
1545         /* add core elements to the ldb_message for the alias */
1546         msg->dn = ldb_dn_build_child(mem_ctx, "CN", sidstr, basedn);
1547         if (msg->dn == NULL)
1548                 return NT_STATUS_NO_MEMORY;
1549         
1550         samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1551                              "objectClass",
1552                              "foreignSecurityPrincipal");
1553         
1554         /* create the alias */
1555         ret = samdb_add(sam_ctx, mem_ctx, msg);
1556         if (ret != 0) {
1557                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1558                          "record %s: %s\n", 
1559                          ldb_dn_linearize(mem_ctx, msg->dn),
1560                          ldb_errstring(sam_ctx)));
1561                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1562         }
1563         *ret_dn = msg->dn;
1564         return NT_STATUS_OK;
1565 }