3c2283a47112ce033ab1633c9a952d0559d337d9
[kamenim/samba.git] / source4 / dsdb / samdb / samdb.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    interface functions for the sam database
5
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Volker Lendecke 2004
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_netlogon.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "librpc/gen_ndr/ndr_security.h"
29 #include "lib/ldb/include/ldb.h"
30 #include "lib/ldb/include/ldb_errors.h"
31 #include "libcli/security/security.h"
32 #include "auth/credentials/credentials.h"
33 #include "libcli/auth/proto.h"
34 #include "libcli/ldap/ldap.h"
35 #include "system/time.h"
36 #include "system/filesys.h"
37 #include "db_wrap.h"
38 #include "dsdb/samdb/samdb.h"
39 #include "ads.h"
40
41 /*
42   connect to the SAM database
43   return an opaque context pointer on success, or NULL on failure
44  */
45 struct ldb_context *samdb_connect(TALLOC_CTX *mem_ctx, 
46                                   struct auth_session_info *session_info)
47 {
48         struct ldb_context *ldb;
49         ldb = ldb_wrap_connect(mem_ctx, lp_sam_url(), session_info,
50                                NULL, 0, NULL);
51         if (!ldb) {
52                 return NULL;
53         }
54         return ldb;
55 }
56
57 /*
58   search the sam for the specified attributes in a specific domain, filter on
59   objectSid being in domain_sid.
60 */
61 int samdb_search_domain(struct ldb_context *sam_ldb,
62                         TALLOC_CTX *mem_ctx, 
63                         const struct ldb_dn *basedn,
64                         struct ldb_message ***res,
65                         const char * const *attrs,
66                         const struct dom_sid *domain_sid,
67                         const char *format, ...)  _PRINTF_ATTRIBUTE(7,8)
68 {
69         va_list ap;
70         int i, count;
71
72         va_start(ap, format);
73         count = gendb_search_v(sam_ldb, mem_ctx, basedn,
74                                res, attrs, format, ap);
75         va_end(ap);
76
77         i=0;
78
79         while (i<count) {
80                 struct dom_sid *entry_sid;
81
82                 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
83
84                 if ((entry_sid == NULL) ||
85                     (!dom_sid_in_domain(domain_sid, entry_sid))) {
86                         /* Delete that entry from the result set */
87                         (*res)[i] = (*res)[count-1];
88                         count -= 1;
89                         talloc_free(entry_sid);
90                         continue;
91                 }
92                 talloc_free(entry_sid);
93                 i += 1;
94         }
95
96         return count;
97 }
98
99 /*
100   search the sam for a single string attribute in exactly 1 record
101 */
102 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
103                                   TALLOC_CTX *mem_ctx,
104                                   const struct ldb_dn *basedn,
105                                   const char *attr_name,
106                                   const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
107 {
108         int count;
109         const char *attrs[2] = { NULL, NULL };
110         struct ldb_message **res = NULL;
111
112         attrs[0] = attr_name;
113
114         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
115         if (count > 1) {                
116                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
117                          attr_name, format, count));
118         }
119         if (count != 1) {
120                 talloc_free(res);
121                 return NULL;
122         }
123
124         return samdb_result_string(res[0], attr_name, NULL);
125 }
126                                  
127
128 /*
129   search the sam for a single string attribute in exactly 1 record
130 */
131 const char *samdb_search_string(struct ldb_context *sam_ldb,
132                                 TALLOC_CTX *mem_ctx,
133                                 const struct ldb_dn *basedn,
134                                 const char *attr_name,
135                                 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
136 {
137         va_list ap;
138         const char *str;
139
140         va_start(ap, format);
141         str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
142         va_end(ap);
143
144         return str;
145 }
146
147 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
148                                TALLOC_CTX *mem_ctx,
149                                const struct ldb_dn *basedn,
150                                const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
151 {
152         va_list ap;
153         struct ldb_dn *ret;
154         struct ldb_message **res = NULL;
155         int count;
156
157         va_start(ap, format);
158         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
159         va_end(ap);
160
161         if (count != 1) return NULL;
162
163         ret = talloc_steal(mem_ctx, res[0]->dn);
164         talloc_free(res);
165
166         return ret;
167 }
168
169 /*
170   search the sam for a dom_sid attribute in exactly 1 record
171 */
172 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
173                                      TALLOC_CTX *mem_ctx,
174                                      const struct ldb_dn *basedn,
175                                      const char *attr_name,
176                                      const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
177 {
178         va_list ap;
179         int count;
180         struct ldb_message **res;
181         const char *attrs[2] = { NULL, NULL };
182         struct dom_sid *sid;
183
184         attrs[0] = attr_name;
185
186         va_start(ap, format);
187         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
188         va_end(ap);
189         if (count > 1) {                
190                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
191                          attr_name, format, count));
192         }
193         if (count != 1) {
194                 talloc_free(res);
195                 return NULL;
196         }
197         sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
198         talloc_free(res);
199         return sid;     
200 }
201
202 /*
203   return the count of the number of records in the sam matching the query
204 */
205 int samdb_search_count(struct ldb_context *sam_ldb,
206                        TALLOC_CTX *mem_ctx,
207                        const struct ldb_dn *basedn,
208                        const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
209 {
210         va_list ap;
211         struct ldb_message **res;
212         const char * const attrs[] = { NULL };
213         int ret;
214
215         va_start(ap, format);
216         ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
217         va_end(ap);
218
219         return ret;
220 }
221
222
223 /*
224   search the sam for a single integer attribute in exactly 1 record
225 */
226 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
227                          TALLOC_CTX *mem_ctx,
228                          uint_t default_value,
229                          const struct ldb_dn *basedn,
230                          const char *attr_name,
231                          const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
232 {
233         va_list ap;
234         int count;
235         struct ldb_message **res;
236         const char *attrs[2] = { NULL, NULL };
237
238         attrs[0] = attr_name;
239
240         va_start(ap, format);
241         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
242         va_end(ap);
243
244         if (count != 1) {
245                 return default_value;
246         }
247
248         return samdb_result_uint(res[0], attr_name, default_value);
249 }
250
251 /*
252   search the sam for a single signed 64 bit integer attribute in exactly 1 record
253 */
254 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
255                            TALLOC_CTX *mem_ctx,
256                            int64_t default_value,
257                            const struct ldb_dn *basedn,
258                            const char *attr_name,
259                            const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
260 {
261         va_list ap;
262         int count;
263         struct ldb_message **res;
264         const char *attrs[2] = { NULL, NULL };
265
266         attrs[0] = attr_name;
267
268         va_start(ap, format);
269         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
270         va_end(ap);
271
272         if (count != 1) {
273                 return default_value;
274         }
275
276         return samdb_result_int64(res[0], attr_name, default_value);
277 }
278
279 /*
280   search the sam for multipe records each giving a single string attribute
281   return the number of matches, or -1 on error
282 */
283 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
284                                  TALLOC_CTX *mem_ctx,
285                                  const struct ldb_dn *basedn,
286                                  const char ***strs,
287                                  const char *attr_name,
288                                  const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
289 {
290         va_list ap;
291         int count, i;
292         const char *attrs[2] = { NULL, NULL };
293         struct ldb_message **res = NULL;
294
295         attrs[0] = attr_name;
296
297         va_start(ap, format);
298         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
299         va_end(ap);
300
301         if (count <= 0) {
302                 return count;
303         }
304
305         /* make sure its single valued */
306         for (i=0;i<count;i++) {
307                 if (res[i]->num_elements != 1) {
308                         DEBUG(1,("samdb: search for %s %s not single valued\n", 
309                                  attr_name, format));
310                         talloc_free(res);
311                         return -1;
312                 }
313         }
314
315         *strs = talloc_array(mem_ctx, const char *, count+1);
316         if (! *strs) {
317                 talloc_free(res);
318                 return -1;
319         }
320
321         for (i=0;i<count;i++) {
322                 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
323         }
324         (*strs)[count] = NULL;
325
326         return count;
327 }
328
329 /*
330   pull a uint from a result set. 
331 */
332 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
333 {
334         return ldb_msg_find_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_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_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_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_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_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 {
679         struct ldb_result *res;
680         struct ldb_message *t;
681         int ret, i, j;
682         
683         struct ldb_dn *basedn = ldb_dn_explode(ldb, "cn=Templates");
684
685         /* pull the template record */
686         ret = ldb_search(ldb, basedn, LDB_SCOPE_SUBTREE, filter, NULL, &res);
687         talloc_free(basedn);
688         if (ret != LDB_SUCCESS) {
689                 return ret;
690         }
691         if (res->count != 1) {
692                 DEBUG(1, ("samdb_copy_template: ERROR: template '%s' matched %d records, expected 1\n", filter, 
693                                                        res->count));
694                 talloc_free(res);
695                 return LDB_ERR_OPERATIONS_ERROR;
696         }
697         t = res->msgs[0];
698
699         for (i = 0; i < t->num_elements; i++) {
700                 struct ldb_message_element *el = &t->elements[i];
701                 /* some elements should not be copied from the template */
702                 if (strcasecmp(el->name, "cn") == 0 ||
703                     strcasecmp(el->name, "name") == 0 ||
704                     strcasecmp(el->name, "sAMAccountName") == 0 ||
705                     strcasecmp(el->name, "objectGUID") == 0) {
706                         continue;
707                 }
708                 for (j = 0; j < el->num_values; j++) {
709                         if (strcasecmp(el->name, "objectClass") == 0) {
710                                 if (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
711                                     strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
712                                     strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
713                                     strcasecmp((char *)el->values[j].data, "foreignSecurityPrincipalTemplate") == 0 ||
714                                     strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 || 
715                                     strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 || 
716                                     strcasecmp((char *)el->values[j].data, "secretTemplate") == 0) {
717                                         continue;
718                                 }
719                                 ret = samdb_find_or_add_value(ldb, msg, el->name, 
720                                                               (char *)el->values[j].data);
721                                 if (ret) {
722                                         DEBUG(1, ( "Adding objectClass %s failed.\n", el->values[j].data));
723                                         talloc_free(res);
724                                         return ret;
725                                 }
726                         } else {
727                                 ret = samdb_find_or_add_attribute(ldb, msg, el->name, 
728                                                                   (char *)el->values[j].data);
729                                 if (ret) {
730                                         DEBUG(1, ("Adding attribute %s failed.\n", el->name));
731                                         talloc_free(res);
732                                         return ret;
733                                 }
734                         }
735                 }
736         }
737
738         talloc_free(res);
739
740         return LDB_SUCCESS;
741 }
742
743
744 /*
745   add a string element to a message
746 */
747 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
748                          const char *attr_name, const char *str)
749 {
750         char *s = talloc_strdup(mem_ctx, str);
751         char *a = talloc_strdup(mem_ctx, attr_name);
752         if (s == NULL || a == NULL) {
753                 return LDB_ERR_OPERATIONS_ERROR;
754         }
755         return ldb_msg_add_string(msg, a, s);
756 }
757
758 /*
759   add a dom_sid element to a message
760 */
761 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
762                          const char *attr_name, struct dom_sid *sid)
763 {
764         struct ldb_val v;
765         NTSTATUS status;
766         status = ndr_push_struct_blob(&v, mem_ctx, sid, 
767                                       (ndr_push_flags_fn_t)ndr_push_dom_sid);
768         if (!NT_STATUS_IS_OK(status)) {
769                 return -1;
770         }
771         return ldb_msg_add_value(msg, attr_name, &v);
772 }
773
774
775 /*
776   add a delete element operation to a message
777 */
778 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
779                          const char *attr_name)
780 {
781         /* we use an empty replace rather than a delete, as it allows for 
782            samdb_replace() to be used everywhere */
783         return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE);
784 }
785
786 /*
787   add a add attribute value to a message
788 */
789 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
790                          const char *attr_name, const char *value)
791 {
792         struct ldb_message_element *el;
793         char *a, *v;
794         int ret;
795         a = talloc_strdup(mem_ctx, attr_name);
796         if (a == NULL)
797                 return -1;
798         v = talloc_strdup(mem_ctx, value);
799         if (v == NULL)
800                 return -1;
801         ret = ldb_msg_add_string(msg, a, v);
802         if (ret != 0)
803                 return ret;
804         el = ldb_msg_find_element(msg, a);
805         if (el == NULL)
806                 return -1;
807         el->flags = LDB_FLAG_MOD_ADD;
808         return 0;
809 }
810
811 /*
812   add a delete attribute value to a message
813 */
814 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
815                          const char *attr_name, const char *value)
816 {
817         struct ldb_message_element *el;
818         char *a, *v;
819         int ret;
820         a = talloc_strdup(mem_ctx, attr_name);
821         if (a == NULL)
822                 return -1;
823         v = talloc_strdup(mem_ctx, value);
824         if (v == NULL)
825                 return -1;
826         ret = ldb_msg_add_string(msg, a, v);
827         if (ret != 0)
828                 return ret;
829         el = ldb_msg_find_element(msg, a);
830         if (el == NULL)
831                 return -1;
832         el->flags = LDB_FLAG_MOD_DELETE;
833         return 0;
834 }
835
836 /*
837   add a int element to a message
838 */
839 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
840                        const char *attr_name, int v)
841 {
842         const char *s = talloc_asprintf(mem_ctx, "%d", v);
843         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
844 }
845
846 /*
847   add a uint_t element to a message
848 */
849 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
850                        const char *attr_name, uint_t v)
851 {
852         const char *s = talloc_asprintf(mem_ctx, "%u", v);
853         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
854 }
855
856 /*
857   add a (signed) int64_t element to a message
858 */
859 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
860                         const char *attr_name, int64_t v)
861 {
862         const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
863         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
864 }
865
866 /*
867   add a uint64_t element to a message
868 */
869 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
870                         const char *attr_name, uint64_t v)
871 {
872         const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
873         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
874 }
875
876 /*
877   add a samr_Password element to a message
878 */
879 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
880                        const char *attr_name, struct samr_Password *hash)
881 {
882         struct ldb_val val;
883         val.data = talloc_memdup(mem_ctx, hash->hash, 16);
884         if (!val.data) {
885                 return -1;
886         }
887         val.length = 16;
888         return ldb_msg_add_value(msg, attr_name, &val);
889 }
890
891 /*
892   add a samr_Password array to a message
893 */
894 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
895                          const char *attr_name, struct samr_Password *hashes, uint_t count)
896 {
897         struct ldb_val val;
898         int i;
899         val.data = talloc_array_size(mem_ctx, 16, count);
900         val.length = count*16;
901         if (!val.data) {
902                 return -1;
903         }
904         for (i=0;i<count;i++) {
905                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
906         }
907         return ldb_msg_add_value(msg, attr_name, &val);
908 }
909
910 /*
911   add a acct_flags element to a message
912 */
913 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
914                              const char *attr_name, uint32_t v)
915 {
916         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
917 }
918
919 /*
920   add a logon_hours element to a message
921 */
922 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
923                               const char *attr_name, struct samr_LogonHours *hours)
924 {
925         struct ldb_val val;
926         val.length = hours->units_per_week / 8;
927         val.data = hours->bits;
928         return ldb_msg_add_value(msg, attr_name, &val);
929 }
930
931 /*
932   add a general value element to a message
933 */
934 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
935                               const char *attr_name, const struct ldb_val *val)
936 {
937         return ldb_msg_add_value(msg, attr_name, val);
938 }
939
940 /*
941   sets a general value element to a message
942 */
943 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
944                         const char *attr_name, const struct ldb_val *val)
945 {
946         struct ldb_message_element *el;
947
948         el = ldb_msg_find_element(msg, attr_name);
949         if (el) {
950                 el->num_values = 0;
951         }
952         return ldb_msg_add_value(msg, attr_name, val);
953 }
954
955 /*
956   set a string element in a message
957 */
958 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
959                          const char *attr_name, const char *str)
960 {
961         struct ldb_message_element *el;
962
963         el = ldb_msg_find_element(msg, attr_name);
964         if (el) {
965                 el->num_values = 0;
966         }
967         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
968 }
969
970 /*
971   add a record
972 */
973 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
974 {
975         return ldb_add(sam_ldb, msg);
976 }
977
978 /*
979   delete a record
980 */
981 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, const struct ldb_dn *dn)
982 {
983         return ldb_delete(sam_ldb, dn);
984 }
985
986 /*
987   modify a record
988 */
989 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
990 {
991         return ldb_modify(sam_ldb, msg);
992 }
993
994 /*
995   replace elements in a record
996 */
997 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
998 {
999         int i;
1000
1001         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1002         for (i=0;i<msg->num_elements;i++) {
1003                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1004         }
1005
1006         /* modify the samdb record */
1007         return samdb_modify(sam_ldb, mem_ctx, msg);
1008 }
1009
1010 /*
1011   return a default security descriptor
1012 */
1013 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1014 {
1015         struct security_descriptor *sd;
1016
1017         sd = security_descriptor_initialise(mem_ctx);
1018
1019         return sd;
1020 }
1021
1022 struct ldb_dn *samdb_base_dn(TALLOC_CTX *mem_ctx) 
1023 {
1024         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1025         int server_role = lp_server_role();
1026         const char **split_realm;
1027         struct ldb_dn *dn;
1028         
1029         if (!tmp_ctx) {
1030                 return NULL;
1031         }
1032
1033         if ((server_role == ROLE_DOMAIN_PDC)
1034             || (server_role == ROLE_DOMAIN_BDC)) {
1035                 int i;
1036                 split_realm = str_list_make(tmp_ctx, lp_realm(), ".");
1037                 if (!split_realm) {
1038                         talloc_free(tmp_ctx);
1039                         return NULL;
1040                 }
1041                 dn = NULL;
1042                 i = str_list_length(split_realm);
1043                 i--;
1044                 for (; i >= 0; i--) {
1045                         dn = ldb_dn_build_child(tmp_ctx, "dc", split_realm[i], dn);
1046                         if (!dn) {
1047                                 talloc_free(tmp_ctx);
1048                                 return NULL;
1049                         }
1050                 }
1051                 return dn;
1052         }
1053         return ldb_dn_string_compose(mem_ctx, NULL, "cn=%s", lp_netbios_name());
1054 }
1055
1056
1057 /*
1058   work out the domain sid for the current open ldb
1059 */
1060 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1061 {
1062         const char *attrs[] = { "rootDomainNamingContext", NULL };
1063         int ret;
1064         struct ldb_result *res = NULL;
1065         TALLOC_CTX *tmp_ctx;
1066         struct dom_sid *domain_sid;
1067         const char *basedn_s;
1068         struct ldb_dn *basedn;
1069
1070         /* see if we have a cached copy */
1071         domain_sid = ldb_get_opaque(ldb, "cache.domain_sid");
1072         if (domain_sid) {
1073                 return domain_sid;
1074         }
1075
1076         tmp_ctx = talloc_new(ldb);
1077         if (tmp_ctx == NULL) {
1078                 goto failed;
1079         }
1080
1081         basedn = ldb_dn_explode(tmp_ctx, "");
1082         if (basedn == NULL) {
1083                 goto failed;
1084         }
1085         
1086         /* find the basedn of the domain from the rootdse */
1087         ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, NULL, attrs, &res);
1088         talloc_steal(tmp_ctx, res);
1089         if (ret != LDB_SUCCESS || res->count != 1) {
1090                 goto failed;
1091         }
1092
1093         basedn_s = ldb_msg_find_string(res->msgs[0], "rootDomainNamingContext", NULL);
1094         if (basedn_s == NULL) {
1095                 goto failed;
1096         }
1097
1098         basedn = ldb_dn_explode(tmp_ctx, basedn_s);
1099         if (basedn == NULL) {
1100                 goto failed;
1101         }
1102
1103         /* find the domain_sid */
1104         domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, basedn, 
1105                                           "objectSid", "objectClass=domainDNS");
1106         if (domain_sid == NULL) {
1107                 goto failed;
1108         }
1109
1110         /* cache the domain_sid in the ldb */
1111         if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1112                 goto failed;
1113         }
1114
1115         talloc_steal(ldb, domain_sid);
1116         talloc_free(tmp_ctx);
1117
1118         return domain_sid;
1119
1120 failed:
1121         DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1122         talloc_free(tmp_ctx);
1123         return NULL;
1124 }
1125
1126 /*
1127   check that a password is sufficiently complex
1128 */
1129 static BOOL samdb_password_complexity_ok(const char *pass)
1130 {
1131         return check_password_quality(pass);
1132 }
1133
1134
1135
1136 /*
1137   set the user password using plaintext, obeying any user or domain
1138   password restrictions
1139
1140   note that this function doesn't actually store the result in the
1141   database, it just fills in the "mod" structure with ldb modify
1142   elements to setup the correct change when samdb_replace() is
1143   called. This allows the caller to combine the change with other
1144   changes (as is needed by some of the set user info levels)
1145
1146   The caller should probably have a transaction wrapping this
1147 */
1148 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1149                             const struct ldb_dn *user_dn,
1150                             const struct ldb_dn *domain_dn,
1151                             struct ldb_message *mod,
1152                             const char *new_pass,
1153                             struct samr_Password *lmNewHash, 
1154                             struct samr_Password *ntNewHash,
1155                             BOOL user_change,
1156                             BOOL restrictions,
1157                             enum samr_RejectReason *reject_reason,
1158                             struct samr_DomInfo1 **_dominfo)
1159 {
1160         const char * const user_attrs[] = { "userAccountControl", "sambaLMPwdHistory", 
1161                                             "sambaNTPwdHistory", 
1162                                             "lmPwdHash", "ntPwdHash", 
1163                                             "objectSid", 
1164                                             "pwdLastSet", NULL };
1165         const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength", 
1166                                               "maxPwdAge", "minPwdAge", 
1167                                               "minPwdLength", NULL };
1168         NTTIME pwdLastSet;
1169         int64_t minPwdAge;
1170         uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1171         uint_t userAccountControl;
1172         struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1173         struct samr_Password local_lmNewHash, local_ntNewHash;
1174         int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1175         struct dom_sid *domain_sid;
1176         struct ldb_message **res;
1177         int count;
1178         time_t now = time(NULL);
1179         NTTIME now_nt;
1180         int i;
1181
1182         /* we need to know the time to compute password age */
1183         unix_to_nt_time(&now_nt, now);
1184
1185         /* pull all the user parameters */
1186         count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1187         if (count != 1) {
1188                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1189         }
1190         userAccountControl = samdb_result_uint(res[0],   "userAccountControl", 0);
1191         sambaLMPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1192                                                  "sambaLMPwdHistory", &sambaLMPwdHistory);
1193         sambaNTPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1194                                                  "sambaNTPwdHistory", &sambaNTPwdHistory);
1195         lmPwdHash =          samdb_result_hash(mem_ctx, res[0],   "lmPwdHash");
1196         ntPwdHash =          samdb_result_hash(mem_ctx, res[0],   "ntPwdHash");
1197         pwdLastSet =         samdb_result_uint64(res[0], "pwdLastSet", 0);
1198
1199         if (domain_dn) {
1200                 /* pull the domain parameters */
1201                 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1202                 if (count != 1) {
1203                         DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n", 
1204                                   ldb_dn_linearize(mem_ctx, domain_dn),
1205                                   ldb_dn_linearize(mem_ctx, user_dn)));
1206                         return NT_STATUS_NO_SUCH_DOMAIN;
1207                 }
1208         } else {
1209                 /* work out the domain sid, and pull the domain from there */
1210                 domain_sid =         samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1211                 if (domain_sid == NULL) {
1212                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1213                 }
1214
1215                 count = gendb_search(ctx, mem_ctx, samdb_base_dn(mem_ctx), &res, domain_attrs, 
1216                                      "(objectSid=%s)", 
1217                                      ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1218                 if (count != 1) {
1219                         DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n", 
1220                                   dom_sid_string(mem_ctx, domain_sid),
1221                                   ldb_dn_linearize(mem_ctx, user_dn)));
1222                         return NT_STATUS_NO_SUCH_DOMAIN;
1223                 }
1224         }
1225
1226         pwdProperties =    samdb_result_uint(res[0],   "pwdProperties", 0);
1227         pwdHistoryLength = samdb_result_uint(res[0],   "pwdHistoryLength", 0);
1228         minPwdLength =     samdb_result_uint(res[0],   "minPwdLength", 0);
1229         minPwdAge =        samdb_result_int64(res[0],  "minPwdAge", 0);
1230
1231         if (_dominfo) {
1232                 struct samr_DomInfo1 *dominfo;
1233                 /* on failure we need to fill in the reject reasons */
1234                 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1235                 if (dominfo == NULL) {
1236                         return NT_STATUS_NO_MEMORY;
1237                 }
1238                 dominfo->min_password_length     = minPwdLength;
1239                 dominfo->password_properties     = pwdProperties;
1240                 dominfo->password_history_length = pwdHistoryLength;
1241                 dominfo->max_password_age        = minPwdAge;
1242                 dominfo->min_password_age        = minPwdAge;
1243                 *_dominfo = dominfo;
1244         }
1245
1246         if (new_pass) {
1247                 /* check the various password restrictions */
1248                 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1249                         if (reject_reason) {
1250                                 *reject_reason = SAMR_REJECT_TOO_SHORT;
1251                         }
1252                         return NT_STATUS_PASSWORD_RESTRICTION;
1253                 }
1254                 
1255                 /* possibly check password complexity */
1256                 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1257                     !samdb_password_complexity_ok(new_pass)) {
1258                         if (reject_reason) {
1259                                 *reject_reason = SAMR_REJECT_COMPLEXITY;
1260                         }
1261                         return NT_STATUS_PASSWORD_RESTRICTION;
1262                 }
1263                 
1264                 /* compute the new nt and lm hashes */
1265                 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1266                         lmNewHash = &local_lmNewHash;
1267                 }
1268                 E_md4hash(new_pass, local_ntNewHash.hash);
1269                 ntNewHash = &local_ntNewHash;
1270         }
1271
1272         if (restrictions && user_change) {
1273                 /* are all password changes disallowed? */
1274                 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1275                         if (reject_reason) {
1276                                 *reject_reason = SAMR_REJECT_OTHER;
1277                         }
1278                         return NT_STATUS_PASSWORD_RESTRICTION;
1279                 }
1280                 
1281                 /* can this user change password? */
1282                 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1283                         if (reject_reason) {
1284                                 *reject_reason = SAMR_REJECT_OTHER;
1285                         }
1286                         return NT_STATUS_PASSWORD_RESTRICTION;
1287                 }
1288                 
1289                 /* yes, this is a minus. The ages are in negative 100nsec units! */
1290                 if (pwdLastSet - minPwdAge > now_nt) {
1291                         if (reject_reason) {
1292                                 *reject_reason = SAMR_REJECT_OTHER;
1293                         }
1294                         return NT_STATUS_PASSWORD_RESTRICTION;
1295                 }
1296
1297                 /* check the immediately past password */
1298                 if (pwdHistoryLength > 0) {
1299                         if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1300                                 if (reject_reason) {
1301                                         *reject_reason = SAMR_REJECT_COMPLEXITY;
1302                                 }
1303                                 return NT_STATUS_PASSWORD_RESTRICTION;
1304                         }
1305                         if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1306                                 if (reject_reason) {
1307                                         *reject_reason = SAMR_REJECT_COMPLEXITY;
1308                                 }
1309                                 return NT_STATUS_PASSWORD_RESTRICTION;
1310                         }
1311                 }
1312                 
1313                 /* check the password history */
1314                 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1315                 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1316                 
1317                 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1318                         if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1319                                 if (reject_reason) {
1320                                         *reject_reason = SAMR_REJECT_COMPLEXITY;
1321                                 }
1322                                 return NT_STATUS_PASSWORD_RESTRICTION;
1323                         }
1324                 }
1325                 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1326                         if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1327                                 if (reject_reason) {
1328                                         *reject_reason = SAMR_REJECT_COMPLEXITY;
1329                                 }
1330                                 return NT_STATUS_PASSWORD_RESTRICTION;
1331                         }
1332                 }
1333         }
1334
1335 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1336
1337         /* the password is acceptable. Start forming the new fields */
1338         if (new_pass) {
1339                 /* if we know the cleartext, then only set it.
1340                  * Modules in ldb will set all the appropriate
1341                  * hashes */
1342                 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod, 
1343                                                "sambaPassword", new_pass));
1344         } else {
1345                 /* We don't have the cleartext, so delete the old one
1346                  * and set what we have of the hashes */
1347                 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1348
1349                 if (lmNewHash) {
1350                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "lmPwdHash", lmNewHash));
1351                 } else {
1352                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHash"));
1353                 }
1354                 
1355                 if (ntNewHash) {
1356                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "ntPwdHash", ntNewHash));
1357                 } else {
1358                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHash"));
1359                 }
1360         }
1361
1362         return NT_STATUS_OK;
1363 }
1364
1365
1366 /*
1367   set the user password using plaintext, obeying any user or domain
1368   password restrictions
1369
1370   This wrapper function takes a SID as input, rather than a user DN,
1371   and actually performs the password change
1372
1373 */
1374 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1375                                 const struct dom_sid *user_sid,
1376                                 const char *new_pass,
1377                                 struct samr_Password *lmNewHash, 
1378                                 struct samr_Password *ntNewHash,
1379                                 BOOL user_change,
1380                                 BOOL restrictions,
1381                                 enum samr_RejectReason *reject_reason,
1382                                 struct samr_DomInfo1 **_dominfo) 
1383 {
1384         NTSTATUS nt_status;
1385         struct ldb_dn *user_dn;
1386         struct ldb_message *msg;
1387         int ret;
1388
1389         ret = ldb_transaction_start(ctx);
1390         if (ret) {
1391                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1392                 return NT_STATUS_TRANSACTION_ABORTED;
1393         }
1394
1395         user_dn = samdb_search_dn(ctx, mem_ctx, samdb_base_dn(mem_ctx), 
1396                                   "(&(objectSid=%s)(objectClass=user))", 
1397                                   ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1398         if (!user_dn) {
1399                 ldb_transaction_cancel(ctx);
1400                 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1401                           dom_sid_string(mem_ctx, user_sid)));
1402                 return NT_STATUS_NO_SUCH_USER;
1403         }
1404
1405         msg = ldb_msg_new(mem_ctx);
1406         if (msg == NULL) {
1407                 ldb_transaction_cancel(ctx);
1408                 return NT_STATUS_NO_MEMORY;
1409         }
1410
1411         msg->dn = ldb_dn_copy(msg, user_dn);
1412         if (!msg->dn) {
1413                 ldb_transaction_cancel(ctx);
1414                 return NT_STATUS_NO_MEMORY;
1415         }
1416
1417         nt_status = samdb_set_password(ctx, mem_ctx,
1418                                        user_dn, NULL,
1419                                        msg, new_pass, 
1420                                        lmNewHash, ntNewHash,
1421                                        user_change, /* This is a password set, not change */
1422                                        restrictions, /* run restriction tests */
1423                                        reject_reason, _dominfo);
1424         if (!NT_STATUS_IS_OK(nt_status)) {
1425                 ldb_transaction_cancel(ctx);
1426                 return nt_status;
1427         }
1428         
1429         /* modify the samdb record */
1430         ret = samdb_replace(ctx, mem_ctx, msg);
1431         if (ret != 0) {
1432                 ldb_transaction_cancel(ctx);
1433                 return NT_STATUS_ACCESS_DENIED;
1434         }
1435
1436         ret = ldb_transaction_commit(ctx);
1437         if (ret != 0) {
1438                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1439                          ldb_dn_linearize(mem_ctx, msg->dn),
1440                          ldb_errstring(ctx)));
1441                 return NT_STATUS_TRANSACTION_ABORTED;
1442         }
1443         return NT_STATUS_OK;
1444 }
1445
1446 /****************************************************************************
1447  Create the SID list for this user.
1448 ****************************************************************************/
1449 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx, 
1450                                struct dom_sid *user_sid,
1451                                struct dom_sid *group_sid, 
1452                                int n_groupSIDs,
1453                                struct dom_sid **groupSIDs, 
1454                                BOOL is_authenticated,
1455                                struct security_token **token)
1456 {
1457         struct security_token *ptoken;
1458         int i;
1459         NTSTATUS status;
1460
1461         ptoken = security_token_initialise(mem_ctx);
1462         NT_STATUS_HAVE_NO_MEMORY(ptoken);
1463
1464         ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1465         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1466
1467         ptoken->user_sid = talloc_reference(ptoken, user_sid);
1468         ptoken->group_sid = talloc_reference(ptoken, group_sid);
1469         ptoken->privilege_mask = 0;
1470
1471         ptoken->sids[0] = ptoken->user_sid;
1472         ptoken->sids[1] = ptoken->group_sid;
1473
1474         /*
1475          * Finally add the "standard" SIDs.
1476          * The only difference between guest and "anonymous"
1477          * is the addition of Authenticated_Users.
1478          */
1479         ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1480         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1481         ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1482         NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1483         ptoken->num_sids = 4;
1484
1485         if (is_authenticated) {
1486                 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1487                 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1488                 ptoken->num_sids++;
1489         }
1490
1491         for (i = 0; i < n_groupSIDs; i++) {
1492                 size_t check_sid_idx;
1493                 for (check_sid_idx = 1; 
1494                      check_sid_idx < ptoken->num_sids; 
1495                      check_sid_idx++) {
1496                         if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1497                                 break;
1498                         }
1499                 }
1500
1501                 if (check_sid_idx == ptoken->num_sids) {
1502                         ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1503                 }
1504         }
1505
1506         /* setup the privilege mask for this token */
1507         status = samdb_privilege_setup(ptoken);
1508         if (!NT_STATUS_IS_OK(status)) {
1509                 talloc_free(ptoken);
1510                 return status;
1511         }
1512
1513         security_token_debug(10, ptoken);
1514
1515         *token = ptoken;
1516
1517         return NT_STATUS_OK;
1518 }
1519
1520
1521 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
1522                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
1523 {
1524         struct ldb_message *msg;
1525         struct ldb_dn *basedn;
1526         const char *sidstr;
1527         int ret;
1528         
1529         sidstr = dom_sid_string(mem_ctx, sid);
1530         NT_STATUS_HAVE_NO_MEMORY(sidstr);
1531         
1532         /* We might have to create a ForeignSecurityPrincipal, even if this user
1533          * is in our own domain */
1534         
1535         msg = ldb_msg_new(mem_ctx);
1536         if (msg == NULL) {
1537                 return NT_STATUS_NO_MEMORY;
1538         }
1539         
1540         /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1541          * put the ForeignSecurityPrincipals? d_state->domain_dn does
1542          * not work, this is wrong for the Builtin domain, there's no
1543          * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
1544          */
1545         
1546         basedn = samdb_search_dn(sam_ctx, mem_ctx, samdb_base_dn(mem_ctx),
1547                                  "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1548         
1549         if (basedn == NULL) {
1550                 DEBUG(0, ("Failed to find DN for "
1551                           "ForeignSecurityPrincipal container\n"));
1552                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1553         }
1554         
1555         /* add core elements to the ldb_message for the alias */
1556         msg->dn = ldb_dn_build_child(mem_ctx, "CN", sidstr, basedn);
1557         if (msg->dn == NULL)
1558                 return NT_STATUS_NO_MEMORY;
1559         
1560         samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1561                              "objectClass",
1562                              "foreignSecurityPrincipal");
1563         
1564         /* create the alias */
1565         ret = samdb_add(sam_ctx, mem_ctx, msg);
1566         if (ret != 0) {
1567                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1568                          "record %s: %s\n", 
1569                          ldb_dn_linearize(mem_ctx, msg->dn),
1570                          ldb_errstring(sam_ctx)));
1571                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1572         }
1573         *ret_dn = msg->dn;
1574         return NT_STATUS_OK;
1575 }