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