s4-ldb: enable version checking in dsdb ldb modules
[samba.git] / source4 / dsdb / samdb / ldb_modules / password_hash.c
1 /* 
2    ldb database module
3
4    Copyright (C) Simo Sorce  2004-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Stefan Metzmacher 2007-2010
8    Copyright (C) Matthias Dieter Wallnöfer 2009-2010
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 3 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, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb password_hash module
28  *
29  *  Description: correctly handle AD password changes fields
30  *
31  *  Author: Andrew Bartlett
32  *  Author: Stefan Metzmacher
33  */
34
35 #include "includes.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "ldb_module.h"
38 #include "librpc/gen_ndr/misc.h"
39 #include "librpc/gen_ndr/samr.h"
40 #include "libcli/auth/libcli_auth.h"
41 #include "libcli/security/security.h"
42 #include "system/kerberos.h"
43 #include "auth/kerberos/kerberos.h"
44 #include "system/time.h"
45 #include "dsdb/samdb/samdb.h"
46 #include "../libds/common/flags.h"
47 #include "dsdb/samdb/ldb_modules/password_modules.h"
48 #include "librpc/ndr/libndr.h"
49 #include "librpc/gen_ndr/ndr_drsblobs.h"
50 #include "../lib/crypto/crypto.h"
51 #include "param/param.h"
52
53 /* If we have decided there is a reason to work on this request, then
54  * setup all the password hash types correctly.
55  *
56  * If we haven't the hashes yet but the password given as plain-text (attributes
57  * 'unicodePwd', 'userPassword' and 'clearTextPassword') we have to check for
58  * the constraints. Once this is done, we calculate the password hashes.
59  *
60  * Notice: unlike the real AD which only supports the UTF16 special based
61  * 'unicodePwd' and the UTF8 based 'userPassword' plaintext attribute we
62  * understand also a UTF16 based 'clearTextPassword' one.
63  * The latter is also accessible through LDAP so it can also be set by external
64  * tools and scripts. But be aware that this isn't portable on non SAMBA 4 ADs!
65  *
66  * Also when the module receives only the password hashes (possible through
67  * specifying an internal LDB control - for security reasons) some checks are
68  * performed depending on the operation mode (see below) (e.g. if the password
69  * has been in use before if the password memory policy was activated).
70  *
71  * Attention: There is a difference between "modify" and "reset" operations
72  * (see MS-ADTS 3.1.1.3.1.5). If the client sends a "add" and "remove"
73  * operation for a password attribute we thread this as a "modify"; if it sends
74  * only a "replace" one we have an (administrative) reset.
75  *
76  * Finally, if the administrator has requested that a password history
77  * be maintained, then this should also be written out.
78  *
79  */
80
81 /* TODO: [consider always MS-ADTS 3.1.1.3.1.5]
82  * - Check for right connection encryption
83  */
84
85 /* Notice: Definition of "dsdb_control_password_change_status" moved into
86  * "samdb.h" */
87
88 struct ph_context {
89         struct ldb_module *module;
90         struct ldb_request *req;
91
92         struct ldb_request *dom_req;
93         struct ldb_reply *dom_res;
94
95         struct ldb_reply *search_res;
96
97         struct dsdb_control_password_change_status *status;
98         struct dsdb_control_password_change *change;
99
100         bool pwd_reset;
101
102         bool change_status;
103         bool hash_values;
104 };
105
106
107 struct setup_password_fields_io {
108         struct ph_context *ac;
109
110         struct smb_krb5_context *smb_krb5_context;
111
112         /* infos about the user account */
113         struct {
114                 uint32_t userAccountControl;
115                 NTTIME pwdLastSet;
116                 const char *sAMAccountName;
117                 const char *user_principal_name;
118                 bool is_computer;
119                 uint32_t restrictions;
120         } u;
121
122         /* new credentials and old given credentials */
123         struct setup_password_fields_given {
124                 const struct ldb_val *cleartext_utf8;
125                 const struct ldb_val *cleartext_utf16;
126                 struct samr_Password *nt_hash;
127                 struct samr_Password *lm_hash;
128         } n, og;
129
130         /* old credentials */
131         struct {
132                 struct samr_Password *nt_hash;
133                 struct samr_Password *lm_hash;
134                 uint32_t nt_history_len;
135                 struct samr_Password *nt_history;
136                 uint32_t lm_history_len;
137                 struct samr_Password *lm_history;
138                 const struct ldb_val *supplemental;
139                 struct supplementalCredentialsBlob scb;
140         } o;
141
142         /* generated credentials */
143         struct {
144                 struct samr_Password *nt_hash;
145                 struct samr_Password *lm_hash;
146                 uint32_t nt_history_len;
147                 struct samr_Password *nt_history;
148                 uint32_t lm_history_len;
149                 struct samr_Password *lm_history;
150                 const char *salt;
151                 DATA_BLOB aes_256;
152                 DATA_BLOB aes_128;
153                 DATA_BLOB des_md5;
154                 DATA_BLOB des_crc;
155                 struct ldb_val supplemental;
156                 NTTIME last_set;
157         } g;
158 };
159
160 /* Get the NT hash, and fill it in as an entry in the password history, 
161    and specify it into io->g.nt_hash */
162
163 static int setup_nt_fields(struct setup_password_fields_io *io)
164 {
165         struct ldb_context *ldb;
166         uint32_t i;
167
168         io->g.nt_hash = io->n.nt_hash;
169         ldb = ldb_module_get_ctx(io->ac->module);
170
171         if (io->ac->status->domain_data.pwdHistoryLength == 0) {
172                 return LDB_SUCCESS;
173         }
174
175         /* We might not have an old NT password */
176         io->g.nt_history = talloc_array(io->ac,
177                                         struct samr_Password,
178                                         io->ac->status->domain_data.pwdHistoryLength);
179         if (!io->g.nt_history) {
180                 return ldb_oom(ldb);
181         }
182
183         for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
184                             io->o.nt_history_len); i++) {
185                 io->g.nt_history[i+1] = io->o.nt_history[i];
186         }
187         io->g.nt_history_len = i + 1;
188
189         if (io->g.nt_hash) {
190                 io->g.nt_history[0] = *io->g.nt_hash;
191         } else {
192                 /* 
193                  * TODO: is this correct?
194                  * the simular behavior is correct for the lm history case
195                  */
196                 E_md4hash("", io->g.nt_history[0].hash);
197         }
198
199         return LDB_SUCCESS;
200 }
201
202 /* Get the LANMAN hash, and fill it in as an entry in the password history, 
203    and specify it into io->g.lm_hash */
204
205 static int setup_lm_fields(struct setup_password_fields_io *io)
206 {
207         struct ldb_context *ldb;
208         uint32_t i;
209
210         io->g.lm_hash = io->n.lm_hash;
211         ldb = ldb_module_get_ctx(io->ac->module);
212
213         if (io->ac->status->domain_data.pwdHistoryLength == 0) {
214                 return LDB_SUCCESS;
215         }
216
217         /* We might not have an old LM password */
218         io->g.lm_history = talloc_array(io->ac,
219                                         struct samr_Password,
220                                         io->ac->status->domain_data.pwdHistoryLength);
221         if (!io->g.lm_history) {
222                 return ldb_oom(ldb);
223         }
224
225         for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
226                             io->o.lm_history_len); i++) {
227                 io->g.lm_history[i+1] = io->o.lm_history[i];
228         }
229         io->g.lm_history_len = i + 1;
230
231         if (io->g.lm_hash) {
232                 io->g.lm_history[0] = *io->g.lm_hash;
233         } else {
234                 E_deshash("", io->g.lm_history[0].hash);
235         }
236
237         return LDB_SUCCESS;
238 }
239
240 static int setup_kerberos_keys(struct setup_password_fields_io *io)
241 {
242         struct ldb_context *ldb;
243         krb5_error_code krb5_ret;
244         Principal *salt_principal;
245         krb5_salt salt;
246         krb5_keyblock key;
247         krb5_data cleartext_data;
248
249         ldb = ldb_module_get_ctx(io->ac->module);
250         cleartext_data.data = io->n.cleartext_utf8->data;
251         cleartext_data.length = io->n.cleartext_utf8->length;
252
253         /* Many, many thanks to lukeh@padl.com for this
254          * algorithm, described in his Nov 10 2004 mail to
255          * samba-technical@samba.org */
256
257         /*
258          * Determine a salting principal
259          */
260         if (io->u.is_computer) {
261                 char *name;
262                 char *saltbody;
263
264                 name = strlower_talloc(io->ac, io->u.sAMAccountName);
265                 if (!name) {
266                         return ldb_oom(ldb);
267                 }
268
269                 if (name[strlen(name)-1] == '$') {
270                         name[strlen(name)-1] = '\0';
271                 }
272
273                 saltbody = talloc_asprintf(io->ac, "%s.%s", name,
274                                            io->ac->status->domain_data.dns_domain);
275                 if (!saltbody) {
276                         return ldb_oom(ldb);
277                 }
278                 
279                 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
280                                                &salt_principal,
281                                                io->ac->status->domain_data.realm,
282                                                "host", saltbody, NULL);
283         } else if (io->u.user_principal_name) {
284                 char *user_principal_name;
285                 char *p;
286
287                 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
288                 if (!user_principal_name) {
289                         return ldb_oom(ldb);
290                 }
291
292                 p = strchr(user_principal_name, '@');
293                 if (p) {
294                         p[0] = '\0';
295                 }
296
297                 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
298                                                &salt_principal,
299                                                io->ac->status->domain_data.realm,
300                                                user_principal_name, NULL);
301         } else {
302                 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
303                                                &salt_principal,
304                                                io->ac->status->domain_data.realm,
305                                                io->u.sAMAccountName, NULL);
306         }
307         if (krb5_ret) {
308                 ldb_asprintf_errstring(ldb,
309                                        "setup_kerberos_keys: "
310                                        "generation of a salting principal failed: %s",
311                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
312                                                                   krb5_ret, io->ac));
313                 return LDB_ERR_OPERATIONS_ERROR;
314         }
315
316         /*
317          * create salt from salt_principal
318          */
319         krb5_ret = krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
320                                     salt_principal, &salt);
321         krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
322         if (krb5_ret) {
323                 ldb_asprintf_errstring(ldb,
324                                        "setup_kerberos_keys: "
325                                        "generation of krb5_salt failed: %s",
326                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
327                                                                   krb5_ret, io->ac));
328                 return LDB_ERR_OPERATIONS_ERROR;
329         }
330         /* create a talloc copy */
331         io->g.salt = talloc_strndup(io->ac,
332                                     (char *)salt.saltvalue.data,
333                                     salt.saltvalue.length);
334         krb5_free_salt(io->smb_krb5_context->krb5_context, salt);
335         if (!io->g.salt) {
336                 return ldb_oom(ldb);
337         }
338         salt.saltvalue.data     = discard_const(io->g.salt);
339         salt.saltvalue.length   = strlen(io->g.salt);
340
341         /*
342          * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
343          * the salt and the cleartext password
344          */
345         krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
346                                                 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
347                                                 cleartext_data,
348                                                 salt,
349                                                 &key);
350         if (krb5_ret) {
351                 ldb_asprintf_errstring(ldb,
352                                        "setup_kerberos_keys: "
353                                        "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
354                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
355                                                                   krb5_ret, io->ac));
356                 return LDB_ERR_OPERATIONS_ERROR;
357         }
358         io->g.aes_256 = data_blob_talloc(io->ac,
359                                          key.keyvalue.data,
360                                          key.keyvalue.length);
361         krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
362         if (!io->g.aes_256.data) {
363                 return ldb_oom(ldb);
364         }
365
366         /*
367          * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
368          * the salt and the cleartext password
369          */
370         krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
371                                                 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
372                                                 cleartext_data,
373                                                 salt,
374                                                 &key);
375         if (krb5_ret) {
376                 ldb_asprintf_errstring(ldb,
377                                        "setup_kerberos_keys: "
378                                        "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
379                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
380                                                                   krb5_ret, io->ac));
381                 return LDB_ERR_OPERATIONS_ERROR;
382         }
383         io->g.aes_128 = data_blob_talloc(io->ac,
384                                          key.keyvalue.data,
385                                          key.keyvalue.length);
386         krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
387         if (!io->g.aes_128.data) {
388                 return ldb_oom(ldb);
389         }
390
391         /*
392          * create ENCTYPE_DES_CBC_MD5 key out of
393          * the salt and the cleartext password
394          */
395         krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
396                                                 ENCTYPE_DES_CBC_MD5,
397                                                 cleartext_data,
398                                                 salt,
399                                                 &key);
400         if (krb5_ret) {
401                 ldb_asprintf_errstring(ldb,
402                                        "setup_kerberos_keys: "
403                                        "generation of a des-cbc-md5 key failed: %s",
404                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
405                                                                   krb5_ret, io->ac));
406                 return LDB_ERR_OPERATIONS_ERROR;
407         }
408         io->g.des_md5 = data_blob_talloc(io->ac,
409                                          key.keyvalue.data,
410                                          key.keyvalue.length);
411         krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
412         if (!io->g.des_md5.data) {
413                 return ldb_oom(ldb);
414         }
415
416         /*
417          * create ENCTYPE_DES_CBC_CRC key out of
418          * the salt and the cleartext password
419          */
420         krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
421                                                 ENCTYPE_DES_CBC_CRC,
422                                                 cleartext_data,
423                                                 salt,
424                                                 &key);
425         if (krb5_ret) {
426                 ldb_asprintf_errstring(ldb,
427                                        "setup_kerberos_keys: "
428                                        "generation of a des-cbc-crc key failed: %s",
429                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
430                                                                   krb5_ret, io->ac));
431                 return LDB_ERR_OPERATIONS_ERROR;
432         }
433         io->g.des_crc = data_blob_talloc(io->ac,
434                                          key.keyvalue.data,
435                                          key.keyvalue.length);
436         krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
437         if (!io->g.des_crc.data) {
438                 return ldb_oom(ldb);
439         }
440
441         return LDB_SUCCESS;
442 }
443
444 static int setup_primary_kerberos(struct setup_password_fields_io *io,
445                                   const struct supplementalCredentialsBlob *old_scb,
446                                   struct package_PrimaryKerberosBlob *pkb)
447 {
448         struct ldb_context *ldb;
449         struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
450         struct supplementalCredentialsPackage *old_scp = NULL;
451         struct package_PrimaryKerberosBlob _old_pkb;
452         struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
453         uint32_t i;
454         enum ndr_err_code ndr_err;
455
456         ldb = ldb_module_get_ctx(io->ac->module);
457
458         /*
459          * prepare generation of keys
460          *
461          * ENCTYPE_DES_CBC_MD5
462          * ENCTYPE_DES_CBC_CRC
463          */
464         pkb->version            = 3;
465         pkb3->salt.string       = io->g.salt;
466         pkb3->num_keys          = 2;
467         pkb3->keys              = talloc_array(io->ac,
468                                                struct package_PrimaryKerberosKey3,
469                                                pkb3->num_keys);
470         if (!pkb3->keys) {
471                 return ldb_oom(ldb);
472         }
473
474         pkb3->keys[0].keytype   = ENCTYPE_DES_CBC_MD5;
475         pkb3->keys[0].value     = &io->g.des_md5;
476         pkb3->keys[1].keytype   = ENCTYPE_DES_CBC_CRC;
477         pkb3->keys[1].value     = &io->g.des_crc;
478
479         /* initialize the old keys to zero */
480         pkb3->num_old_keys      = 0;
481         pkb3->old_keys          = NULL;
482
483         /* if there're no old keys, then we're done */
484         if (!old_scb) {
485                 return LDB_SUCCESS;
486         }
487
488         for (i=0; i < old_scb->sub.num_packages; i++) {
489                 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
490                         continue;
491                 }
492
493                 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
494                         continue;
495                 }
496
497                 old_scp = &old_scb->sub.packages[i];
498                 break;
499         }
500         /* Primary:Kerberos element of supplementalCredentials */
501         if (old_scp) {
502                 DATA_BLOB blob;
503
504                 blob = strhex_to_data_blob(io->ac, old_scp->data);
505                 if (!blob.data) {
506                         return ldb_oom(ldb);
507                 }
508
509                 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
510                 ndr_err = ndr_pull_struct_blob(&blob, io->ac, &_old_pkb,
511                                                (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
512                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
513                         NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
514                         ldb_asprintf_errstring(ldb,
515                                                "setup_primary_kerberos: "
516                                                "failed to pull old package_PrimaryKerberosBlob: %s",
517                                                nt_errstr(status));
518                         return LDB_ERR_OPERATIONS_ERROR;
519                 }
520
521                 if (_old_pkb.version != 3) {
522                         ldb_asprintf_errstring(ldb,
523                                                "setup_primary_kerberos: "
524                                                "package_PrimaryKerberosBlob version[%u] expected[3]",
525                                                _old_pkb.version);
526                         return LDB_ERR_OPERATIONS_ERROR;
527                 }
528
529                 old_pkb3 = &_old_pkb.ctr.ctr3;
530         }
531
532         /* if we didn't found the old keys we're done */
533         if (!old_pkb3) {
534                 return LDB_SUCCESS;
535         }
536
537         /* fill in the old keys */
538         pkb3->num_old_keys      = old_pkb3->num_keys;
539         pkb3->old_keys          = old_pkb3->keys;
540
541         return LDB_SUCCESS;
542 }
543
544 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
545                                         const struct supplementalCredentialsBlob *old_scb,
546                                         struct package_PrimaryKerberosBlob *pkb)
547 {
548         struct ldb_context *ldb;
549         struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
550         struct supplementalCredentialsPackage *old_scp = NULL;
551         struct package_PrimaryKerberosBlob _old_pkb;
552         struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
553         uint32_t i;
554         enum ndr_err_code ndr_err;
555
556         ldb = ldb_module_get_ctx(io->ac->module);
557
558         /*
559          * prepare generation of keys
560          *
561          * ENCTYPE_AES256_CTS_HMAC_SHA1_96
562          * ENCTYPE_AES128_CTS_HMAC_SHA1_96
563          * ENCTYPE_DES_CBC_MD5
564          * ENCTYPE_DES_CBC_CRC
565          */
566         pkb->version                    = 4;
567         pkb4->salt.string               = io->g.salt;
568         pkb4->default_iteration_count   = 4096;
569         pkb4->num_keys                  = 4;
570
571         pkb4->keys = talloc_array(io->ac,
572                                   struct package_PrimaryKerberosKey4,
573                                   pkb4->num_keys);
574         if (!pkb4->keys) {
575                 return ldb_oom(ldb);
576         }
577
578         pkb4->keys[0].iteration_count   = 4096;
579         pkb4->keys[0].keytype           = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
580         pkb4->keys[0].value             = &io->g.aes_256;
581         pkb4->keys[1].iteration_count   = 4096;
582         pkb4->keys[1].keytype           = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
583         pkb4->keys[1].value             = &io->g.aes_128;
584         pkb4->keys[2].iteration_count   = 4096;
585         pkb4->keys[2].keytype           = ENCTYPE_DES_CBC_MD5;
586         pkb4->keys[2].value             = &io->g.des_md5;
587         pkb4->keys[3].iteration_count   = 4096;
588         pkb4->keys[3].keytype           = ENCTYPE_DES_CBC_CRC;
589         pkb4->keys[3].value             = &io->g.des_crc;
590
591         /* initialize the old keys to zero */
592         pkb4->num_old_keys      = 0;
593         pkb4->old_keys          = NULL;
594         pkb4->num_older_keys    = 0;
595         pkb4->older_keys        = NULL;
596
597         /* if there're no old keys, then we're done */
598         if (!old_scb) {
599                 return LDB_SUCCESS;
600         }
601
602         for (i=0; i < old_scb->sub.num_packages; i++) {
603                 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
604                         continue;
605                 }
606
607                 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
608                         continue;
609                 }
610
611                 old_scp = &old_scb->sub.packages[i];
612                 break;
613         }
614         /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
615         if (old_scp) {
616                 DATA_BLOB blob;
617
618                 blob = strhex_to_data_blob(io->ac, old_scp->data);
619                 if (!blob.data) {
620                         return ldb_oom(ldb);
621                 }
622
623                 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
624                 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
625                                                &_old_pkb,
626                                                (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
627                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
628                         NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
629                         ldb_asprintf_errstring(ldb,
630                                                "setup_primary_kerberos_newer: "
631                                                "failed to pull old package_PrimaryKerberosBlob: %s",
632                                                nt_errstr(status));
633                         return LDB_ERR_OPERATIONS_ERROR;
634                 }
635
636                 if (_old_pkb.version != 4) {
637                         ldb_asprintf_errstring(ldb,
638                                                "setup_primary_kerberos_newer: "
639                                                "package_PrimaryKerberosBlob version[%u] expected[4]",
640                                                _old_pkb.version);
641                         return LDB_ERR_OPERATIONS_ERROR;
642                 }
643
644                 old_pkb4 = &_old_pkb.ctr.ctr4;
645         }
646
647         /* if we didn't found the old keys we're done */
648         if (!old_pkb4) {
649                 return LDB_SUCCESS;
650         }
651
652         /* fill in the old keys */
653         pkb4->num_old_keys      = old_pkb4->num_keys;
654         pkb4->old_keys          = old_pkb4->keys;
655         pkb4->num_older_keys    = old_pkb4->num_old_keys;
656         pkb4->older_keys        = old_pkb4->old_keys;
657
658         return LDB_SUCCESS;
659 }
660
661 static int setup_primary_wdigest(struct setup_password_fields_io *io,
662                                  const struct supplementalCredentialsBlob *old_scb,
663                                  struct package_PrimaryWDigestBlob *pdb)
664 {
665         struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
666         DATA_BLOB sAMAccountName;
667         DATA_BLOB sAMAccountName_l;
668         DATA_BLOB sAMAccountName_u;
669         const char *user_principal_name = io->u.user_principal_name;
670         DATA_BLOB userPrincipalName;
671         DATA_BLOB userPrincipalName_l;
672         DATA_BLOB userPrincipalName_u;
673         DATA_BLOB netbios_domain;
674         DATA_BLOB netbios_domain_l;
675         DATA_BLOB netbios_domain_u;
676         DATA_BLOB dns_domain;
677         DATA_BLOB dns_domain_l;
678         DATA_BLOB dns_domain_u;
679         DATA_BLOB digest;
680         DATA_BLOB delim;
681         DATA_BLOB backslash;
682         uint8_t i;
683         struct {
684                 DATA_BLOB *user;
685                 DATA_BLOB *realm;
686                 DATA_BLOB *nt4dom;
687         } wdigest[] = {
688         /*
689          * See
690          * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
691          * for what precalculated hashes are supposed to be stored...
692          *
693          * I can't reproduce all values which should contain "Digest" as realm,
694          * am I doing something wrong or is w2k3 just broken...?
695          *
696          * W2K3 fills in following for a user:
697          *
698          * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
699          * sAMAccountName: NewUser2Sam
700          * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
701          *
702          * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
703          * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
704          * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
705          * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
706          * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
707          * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
708          * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
709          * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
710          * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
711          * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
712          * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
713          * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
714          * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
715          * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
716          * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
717          * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
718          * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
719          * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
720          * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
721          * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
722          * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
723          * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
724          * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
725          * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
726          * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
727          * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
728          * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
729          * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
730          * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
731          *
732          * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
733          * sAMAccountName: NewUser2Sam
734          *
735          * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
736          * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
737          * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
738          * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
739          * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
740          * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
741          * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
742          * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
743          * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
744          * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
745          * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
746          * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
747          * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
748          * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
749          * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
750          * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
751          * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
752          * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
753          * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
754          * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
755          * 31dc704d3640335b2123d4ee28aa1f11 => ???M1   changes with NewUser2Sam => NewUser1Sam
756          * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
757          * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
758          * 569b4533f2d9e580211dd040e5e360a8 => ???M2   changes with NewUser2Princ => NewUser1Princ
759          * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
760          * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
761          * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
762          * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
763          * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
764          */
765
766         /*
767          * sAMAccountName, netbios_domain
768          */
769                 {
770                 .user   = &sAMAccountName,
771                 .realm  = &netbios_domain,
772                 },
773                 {
774                 .user   = &sAMAccountName_l,
775                 .realm  = &netbios_domain_l,
776                 },
777                 {
778                 .user   = &sAMAccountName_u,
779                 .realm  = &netbios_domain_u,
780                 },
781                 {
782                 .user   = &sAMAccountName,
783                 .realm  = &netbios_domain_u,
784                 },
785                 {
786                 .user   = &sAMAccountName,
787                 .realm  = &netbios_domain_l,
788                 },
789                 {
790                 .user   = &sAMAccountName_u,
791                 .realm  = &netbios_domain_l,
792                 },
793                 {
794                 .user   = &sAMAccountName_l,
795                 .realm  = &netbios_domain_u,
796                 },
797         /* 
798          * sAMAccountName, dns_domain
799          */
800                 {
801                 .user   = &sAMAccountName,
802                 .realm  = &dns_domain,
803                 },
804                 {
805                 .user   = &sAMAccountName_l,
806                 .realm  = &dns_domain_l,
807                 },
808                 {
809                 .user   = &sAMAccountName_u,
810                 .realm  = &dns_domain_u,
811                 },
812                 {
813                 .user   = &sAMAccountName,
814                 .realm  = &dns_domain_u,
815                 },
816                 {
817                 .user   = &sAMAccountName,
818                 .realm  = &dns_domain_l,
819                 },
820                 {
821                 .user   = &sAMAccountName_u,
822                 .realm  = &dns_domain_l,
823                 },
824                 {
825                 .user   = &sAMAccountName_l,
826                 .realm  = &dns_domain_u,
827                 },
828         /* 
829          * userPrincipalName, no realm
830          */
831                 {
832                 .user   = &userPrincipalName,
833                 },
834                 {
835                 /* 
836                  * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
837                  *       the fallback to the sAMAccountName based userPrincipalName is correct
838                  */
839                 .user   = &userPrincipalName_l,
840                 },
841                 {
842                 .user   = &userPrincipalName_u,
843                 },
844         /* 
845          * nt4dom\sAMAccountName, no realm
846          */
847                 {
848                 .user   = &sAMAccountName,
849                 .nt4dom = &netbios_domain
850                 },
851                 {
852                 .user   = &sAMAccountName_l,
853                 .nt4dom = &netbios_domain_l
854                 },
855                 {
856                 .user   = &sAMAccountName_u,
857                 .nt4dom = &netbios_domain_u
858                 },
859
860         /*
861          * the following ones are guessed depending on the technet2 article
862          * but not reproducable on a w2k3 server
863          */
864         /* sAMAccountName with "Digest" realm */
865                 {
866                 .user   = &sAMAccountName,
867                 .realm  = &digest
868                 },
869                 {
870                 .user   = &sAMAccountName_l,
871                 .realm  = &digest
872                 },
873                 {
874                 .user   = &sAMAccountName_u,
875                 .realm  = &digest
876                 },
877         /* userPrincipalName with "Digest" realm */
878                 {
879                 .user   = &userPrincipalName,
880                 .realm  = &digest
881                 },
882                 {
883                 .user   = &userPrincipalName_l,
884                 .realm  = &digest
885                 },
886                 {
887                 .user   = &userPrincipalName_u,
888                 .realm  = &digest
889                 },
890         /* nt4dom\\sAMAccountName with "Digest" realm */
891                 {
892                 .user   = &sAMAccountName,
893                 .nt4dom = &netbios_domain,
894                 .realm  = &digest
895                 },
896                 {
897                 .user   = &sAMAccountName_l,
898                 .nt4dom = &netbios_domain_l,
899                 .realm  = &digest
900                 },
901                 {
902                 .user   = &sAMAccountName_u,
903                 .nt4dom = &netbios_domain_u,
904                 .realm  = &digest
905                 },
906         };
907
908         /* prepare DATA_BLOB's used in the combinations array */
909         sAMAccountName          = data_blob_string_const(io->u.sAMAccountName);
910         sAMAccountName_l        = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
911         if (!sAMAccountName_l.data) {
912                 return ldb_oom(ldb);
913         }
914         sAMAccountName_u        = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
915         if (!sAMAccountName_u.data) {
916                 return ldb_oom(ldb);
917         }
918
919         /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
920         if (!user_principal_name) {
921                 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
922                                                       io->u.sAMAccountName,
923                                                       io->ac->status->domain_data.dns_domain);
924                 if (!user_principal_name) {
925                         return ldb_oom(ldb);
926                 }       
927         }
928         userPrincipalName       = data_blob_string_const(user_principal_name);
929         userPrincipalName_l     = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
930         if (!userPrincipalName_l.data) {
931                 return ldb_oom(ldb);
932         }
933         userPrincipalName_u     = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
934         if (!userPrincipalName_u.data) {
935                 return ldb_oom(ldb);
936         }
937
938         netbios_domain          = data_blob_string_const(io->ac->status->domain_data.netbios_domain);
939         netbios_domain_l        = data_blob_string_const(strlower_talloc(io->ac,
940                                                                          io->ac->status->domain_data.netbios_domain));
941         if (!netbios_domain_l.data) {
942                 return ldb_oom(ldb);
943         }
944         netbios_domain_u        = data_blob_string_const(strupper_talloc(io->ac,
945                                                                          io->ac->status->domain_data.netbios_domain));
946         if (!netbios_domain_u.data) {
947                 return ldb_oom(ldb);
948         }
949
950         dns_domain              = data_blob_string_const(io->ac->status->domain_data.dns_domain);
951         dns_domain_l            = data_blob_string_const(io->ac->status->domain_data.dns_domain);
952         dns_domain_u            = data_blob_string_const(io->ac->status->domain_data.realm);
953
954         digest                  = data_blob_string_const("Digest");
955
956         delim                   = data_blob_string_const(":");
957         backslash               = data_blob_string_const("\\");
958
959         pdb->num_hashes = ARRAY_SIZE(wdigest);
960         pdb->hashes     = talloc_array(io->ac, struct package_PrimaryWDigestHash,
961                                        pdb->num_hashes);
962         if (!pdb->hashes) {
963                 return ldb_oom(ldb);
964         }
965
966         for (i=0; i < ARRAY_SIZE(wdigest); i++) {
967                 struct MD5Context md5;
968                 MD5Init(&md5);
969                 if (wdigest[i].nt4dom) {
970                         MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
971                         MD5Update(&md5, backslash.data, backslash.length);
972                 }
973                 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
974                 MD5Update(&md5, delim.data, delim.length);
975                 if (wdigest[i].realm) {
976                         MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
977                 }
978                 MD5Update(&md5, delim.data, delim.length);
979                 MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
980                 MD5Final(pdb->hashes[i].hash, &md5);
981         }
982
983         return LDB_SUCCESS;
984 }
985
986 static int setup_supplemental_field(struct setup_password_fields_io *io)
987 {
988         struct ldb_context *ldb;
989         struct supplementalCredentialsBlob scb;
990         struct supplementalCredentialsBlob _old_scb;
991         struct supplementalCredentialsBlob *old_scb = NULL;
992         /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
993         uint32_t num_names = 0;
994         const char *names[1+4];
995         uint32_t num_packages = 0;
996         struct supplementalCredentialsPackage packages[1+4];
997         /* Packages */
998         struct supplementalCredentialsPackage *pp = NULL;
999         struct package_PackagesBlob pb;
1000         DATA_BLOB pb_blob;
1001         char *pb_hexstr;
1002         /* Primary:Kerberos-Newer-Keys */
1003         const char **nkn = NULL;
1004         struct supplementalCredentialsPackage *pkn = NULL;
1005         struct package_PrimaryKerberosBlob pknb;
1006         DATA_BLOB pknb_blob;
1007         char *pknb_hexstr;
1008         /* Primary:Kerberos */
1009         const char **nk = NULL;
1010         struct supplementalCredentialsPackage *pk = NULL;
1011         struct package_PrimaryKerberosBlob pkb;
1012         DATA_BLOB pkb_blob;
1013         char *pkb_hexstr;
1014         /* Primary:WDigest */
1015         const char **nd = NULL;
1016         struct supplementalCredentialsPackage *pd = NULL;
1017         struct package_PrimaryWDigestBlob pdb;
1018         DATA_BLOB pdb_blob;
1019         char *pdb_hexstr;
1020         /* Primary:CLEARTEXT */
1021         const char **nc = NULL;
1022         struct supplementalCredentialsPackage *pc = NULL;
1023         struct package_PrimaryCLEARTEXTBlob pcb;
1024         DATA_BLOB pcb_blob;
1025         char *pcb_hexstr;
1026         int ret;
1027         enum ndr_err_code ndr_err;
1028         uint8_t zero16[16];
1029         bool do_newer_keys = false;
1030         bool do_cleartext = false;
1031
1032         ZERO_STRUCT(zero16);
1033         ZERO_STRUCT(names);
1034
1035         ldb = ldb_module_get_ctx(io->ac->module);
1036
1037         if (!io->n.cleartext_utf8) {
1038                 /* 
1039                  * when we don't have a cleartext password
1040                  * we can't setup a supplementalCredential value
1041                  */
1042                 return LDB_SUCCESS;
1043         }
1044
1045         /* if there's an old supplementaCredentials blob then parse it */
1046         if (io->o.supplemental) {
1047                 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
1048                                                    &_old_scb,
1049                                                    (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
1050                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1051                         NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1052                         ldb_asprintf_errstring(ldb,
1053                                                "setup_supplemental_field: "
1054                                                "failed to pull old supplementalCredentialsBlob: %s",
1055                                                nt_errstr(status));
1056                         return LDB_ERR_OPERATIONS_ERROR;
1057                 }
1058
1059                 if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1060                         old_scb = &_old_scb;
1061                 } else {
1062                         ldb_debug(ldb, LDB_DEBUG_ERROR,
1063                                                "setup_supplemental_field: "
1064                                                "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1065                                                _old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1066                 }
1067         }
1068         /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
1069         do_newer_keys = (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008);
1070
1071         if (io->ac->status->domain_data.store_cleartext &&
1072             (io->u.userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1073                 do_cleartext = true;
1074         }
1075
1076         /*
1077          * The ordering is this
1078          *
1079          * Primary:Kerberos-Newer-Keys (optional)
1080          * Primary:Kerberos
1081          * Primary:WDigest
1082          * Primary:CLEARTEXT (optional)
1083          *
1084          * And the 'Packages' package is insert before the last
1085          * other package.
1086          */
1087         if (do_newer_keys) {
1088                 /* Primary:Kerberos-Newer-Keys */
1089                 nkn = &names[num_names++];
1090                 pkn = &packages[num_packages++];
1091         }
1092
1093         /* Primary:Kerberos */
1094         nk = &names[num_names++];
1095         pk = &packages[num_packages++];
1096
1097         if (!do_cleartext) {
1098                 /* Packages */
1099                 pp = &packages[num_packages++];
1100         }
1101
1102         /* Primary:WDigest */
1103         nd = &names[num_names++];
1104         pd = &packages[num_packages++];
1105
1106         if (do_cleartext) {
1107                 /* Packages */
1108                 pp = &packages[num_packages++];
1109
1110                 /* Primary:CLEARTEXT */
1111                 nc = &names[num_names++];
1112                 pc = &packages[num_packages++];
1113         }
1114
1115         if (pkn) {
1116                 /*
1117                  * setup 'Primary:Kerberos-Newer-Keys' element
1118                  */
1119                 *nkn = "Kerberos-Newer-Keys";
1120
1121                 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1122                 if (ret != LDB_SUCCESS) {
1123                         return ret;
1124                 }
1125
1126                 ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1127                                                &pknb,
1128                                                (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1129                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1130                         NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1131                         ldb_asprintf_errstring(ldb,
1132                                                "setup_supplemental_field: "
1133                                                "failed to push package_PrimaryKerberosNeverBlob: %s",
1134                                                nt_errstr(status));
1135                         return LDB_ERR_OPERATIONS_ERROR;
1136                 }
1137                 pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
1138                 if (!pknb_hexstr) {
1139                         return ldb_oom(ldb);
1140                 }
1141                 pkn->name       = "Primary:Kerberos-Newer-Keys";
1142                 pkn->reserved   = 1;
1143                 pkn->data       = pknb_hexstr;
1144         }
1145
1146         /*
1147          * setup 'Primary:Kerberos' element
1148          */
1149         *nk = "Kerberos";
1150
1151         ret = setup_primary_kerberos(io, old_scb, &pkb);
1152         if (ret != LDB_SUCCESS) {
1153                 return ret;
1154         }
1155
1156         ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac, 
1157                                        &pkb,
1158                                        (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1159         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1160                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1161                 ldb_asprintf_errstring(ldb,
1162                                        "setup_supplemental_field: "
1163                                        "failed to push package_PrimaryKerberosBlob: %s",
1164                                        nt_errstr(status));
1165                 return LDB_ERR_OPERATIONS_ERROR;
1166         }
1167         pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
1168         if (!pkb_hexstr) {
1169                 return ldb_oom(ldb);
1170         }
1171         pk->name        = "Primary:Kerberos";
1172         pk->reserved    = 1;
1173         pk->data        = pkb_hexstr;
1174
1175         /*
1176          * setup 'Primary:WDigest' element
1177          */
1178         *nd = "WDigest";
1179
1180         ret = setup_primary_wdigest(io, old_scb, &pdb);
1181         if (ret != LDB_SUCCESS) {
1182                 return ret;
1183         }
1184
1185         ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac, 
1186                                        &pdb,
1187                                        (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1188         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1189                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1190                 ldb_asprintf_errstring(ldb,
1191                                        "setup_supplemental_field: "
1192                                        "failed to push package_PrimaryWDigestBlob: %s",
1193                                        nt_errstr(status));
1194                 return LDB_ERR_OPERATIONS_ERROR;
1195         }
1196         pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
1197         if (!pdb_hexstr) {
1198                 return ldb_oom(ldb);
1199         }
1200         pd->name        = "Primary:WDigest";
1201         pd->reserved    = 1;
1202         pd->data        = pdb_hexstr;
1203
1204         /*
1205          * setup 'Primary:CLEARTEXT' element
1206          */
1207         if (pc) {
1208                 *nc             = "CLEARTEXT";
1209
1210                 pcb.cleartext   = *io->n.cleartext_utf16;
1211
1212                 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac, 
1213                                                &pcb,
1214                                                (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1215                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1216                         NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1217                         ldb_asprintf_errstring(ldb,
1218                                                "setup_supplemental_field: "
1219                                                "failed to push package_PrimaryCLEARTEXTBlob: %s",
1220                                                nt_errstr(status));
1221                         return LDB_ERR_OPERATIONS_ERROR;
1222                 }
1223                 pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
1224                 if (!pcb_hexstr) {
1225                         return ldb_oom(ldb);
1226                 }
1227                 pc->name        = "Primary:CLEARTEXT";
1228                 pc->reserved    = 1;
1229                 pc->data        = pcb_hexstr;
1230         }
1231
1232         /*
1233          * setup 'Packages' element
1234          */
1235         pb.names = names;
1236         ndr_err = ndr_push_struct_blob(&pb_blob, io->ac, 
1237                                        &pb,
1238                                        (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1239         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1240                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1241                 ldb_asprintf_errstring(ldb,
1242                                        "setup_supplemental_field: "
1243                                        "failed to push package_PackagesBlob: %s",
1244                                        nt_errstr(status));
1245                 return LDB_ERR_OPERATIONS_ERROR;
1246         }
1247         pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
1248         if (!pb_hexstr) {
1249                 return ldb_oom(ldb);
1250         }
1251         pp->name        = "Packages";
1252         pp->reserved    = 2;
1253         pp->data        = pb_hexstr;
1254
1255         /*
1256          * setup 'supplementalCredentials' value
1257          */
1258         ZERO_STRUCT(scb);
1259         scb.sub.num_packages    = num_packages;
1260         scb.sub.packages        = packages;
1261
1262         ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac, 
1263                                        &scb,
1264                                        (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1265         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1266                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1267                 ldb_asprintf_errstring(ldb,
1268                                        "setup_supplemental_field: "
1269                                        "failed to push supplementalCredentialsBlob: %s",
1270                                        nt_errstr(status));
1271                 return LDB_ERR_OPERATIONS_ERROR;
1272         }
1273
1274         return LDB_SUCCESS;
1275 }
1276
1277 static int setup_last_set_field(struct setup_password_fields_io *io)
1278 {
1279         /* set it as now */
1280         unix_to_nt_time(&io->g.last_set, time(NULL));
1281
1282         return LDB_SUCCESS;
1283 }
1284
1285 static int setup_given_passwords(struct setup_password_fields_io *io,
1286                                  struct setup_password_fields_given *g)
1287 {
1288         struct ldb_context *ldb;
1289         bool ok;
1290
1291         ldb = ldb_module_get_ctx(io->ac->module);
1292
1293         if (g->cleartext_utf8) {
1294                 char **cleartext_utf16_str;
1295                 struct ldb_val *cleartext_utf16_blob;
1296                 size_t converted_pw_len;
1297
1298                 cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
1299                 if (!cleartext_utf16_blob) {
1300                         return ldb_oom(ldb);
1301                 }
1302                 if (!convert_string_talloc(io->ac,
1303                                                        CH_UTF8, CH_UTF16,
1304                                                        g->cleartext_utf8->data,
1305                                                        g->cleartext_utf8->length,
1306                                                        (void *)&cleartext_utf16_str,
1307                                                        &converted_pw_len, false)) {
1308                         ldb_asprintf_errstring(ldb,
1309                                 "setup_password_fields: "
1310                                 "failed to generate UTF16 password from cleartext UTF8 password");
1311                         return LDB_ERR_OPERATIONS_ERROR;
1312                 }
1313                 *cleartext_utf16_blob = data_blob_const(cleartext_utf16_str,
1314                                                         converted_pw_len);
1315                 g->cleartext_utf16 = cleartext_utf16_blob;
1316         } else if (g->cleartext_utf16) {
1317                 char *cleartext_utf8_str;
1318                 struct ldb_val *cleartext_utf8_blob;
1319                 size_t converted_pw_len;
1320
1321                 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
1322                 if (!cleartext_utf8_blob) {
1323                         return ldb_oom(ldb);
1324                 }
1325                 if (!convert_string_talloc(io->ac,
1326                                                        CH_UTF16MUNGED, CH_UTF8,
1327                                                        g->cleartext_utf16->data,
1328                                                        g->cleartext_utf16->length,
1329                                                        (void *)&cleartext_utf8_str,
1330                                                        &converted_pw_len, false)) {
1331                         /* We can't bail out entirely, as these unconvertable passwords are frustratingly valid */
1332                         talloc_free(cleartext_utf8_blob);
1333                 } else {
1334                         *cleartext_utf8_blob = data_blob_const(cleartext_utf8_str,
1335                                                                converted_pw_len);
1336                         g->cleartext_utf8 = cleartext_utf8_blob;
1337                 }
1338         }
1339
1340         if (g->cleartext_utf16) {
1341                 struct samr_Password *nt_hash;
1342
1343                 nt_hash = talloc(io->ac, struct samr_Password);
1344                 if (!nt_hash) {
1345                         return ldb_oom(ldb);
1346                 }
1347                 g->nt_hash = nt_hash;
1348
1349                 /* compute the new nt hash */
1350                 mdfour(nt_hash->hash,
1351                        g->cleartext_utf16->data,
1352                        g->cleartext_utf16->length);
1353         }
1354
1355         if (g->cleartext_utf8) {
1356                 struct samr_Password *lm_hash;
1357
1358                 lm_hash = talloc(io->ac, struct samr_Password);
1359                 if (!lm_hash) {
1360                         return ldb_oom(ldb);
1361                 }
1362
1363                 /* compute the new lm hash */
1364                 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
1365                 if (ok) {
1366                         g->lm_hash = lm_hash;
1367                 } else {
1368                         talloc_free(lm_hash);
1369                 }
1370         }
1371
1372         return LDB_SUCCESS;
1373 }
1374
1375 static int setup_password_fields(struct setup_password_fields_io *io)
1376 {
1377         struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1378         struct loadparm_context *lp_ctx =
1379                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1380                                          struct loadparm_context);
1381         int ret;
1382
1383         /* transform the old password (for password changes) */
1384         ret = setup_given_passwords(io, &io->og);
1385         if (ret != LDB_SUCCESS) {
1386                 return ret;
1387         }
1388
1389         /* transform the new password */
1390         ret = setup_given_passwords(io, &io->n);
1391         if (ret != LDB_SUCCESS) {
1392                 return ret;
1393         }
1394
1395         if (io->n.cleartext_utf8) {
1396                 ret = setup_kerberos_keys(io);
1397                 if (ret != LDB_SUCCESS) {
1398                         return ret;
1399                 }
1400         }
1401
1402         ret = setup_nt_fields(io);
1403         if (ret != LDB_SUCCESS) {
1404                 return ret;
1405         }
1406
1407         if (lpcfg_lanman_auth(lp_ctx)) {
1408                 ret = setup_lm_fields(io);
1409                 if (ret != LDB_SUCCESS) {
1410                         return ret;
1411                 }
1412         } else {
1413                 io->g.lm_hash = NULL;
1414                 io->g.lm_history_len = 0;
1415         }
1416
1417         ret = setup_supplemental_field(io);
1418         if (ret != LDB_SUCCESS) {
1419                 return ret;
1420         }
1421
1422         ret = setup_last_set_field(io);
1423         if (ret != LDB_SUCCESS) {
1424                 return ret;
1425         }
1426
1427         return LDB_SUCCESS;
1428 }
1429
1430 static int check_password_restrictions(struct setup_password_fields_io *io)
1431 {
1432         struct ldb_context *ldb;
1433         int ret;
1434         enum samr_ValidationStatus stat;
1435
1436         ldb = ldb_module_get_ctx(io->ac->module);
1437
1438         /* First check the old password is correct, for password changes */
1439         if (!io->ac->pwd_reset) {
1440                 bool nt_hash_checked = false;
1441
1442                 /* we need the old nt or lm hash given by the client */
1443                 if (!io->og.nt_hash && !io->og.lm_hash) {
1444                         ldb_asprintf_errstring(ldb,
1445                                 "check_password_restrictions: "
1446                                 "You need to provide the old password in order "
1447                                 "to change it!");
1448                         return LDB_ERR_UNWILLING_TO_PERFORM;
1449                 }
1450
1451                 /* The password modify through the NT hash is encouraged and
1452                    has no problems at all */
1453                 if (io->og.nt_hash) {
1454                         if (!io->o.nt_hash) {
1455                                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1456                                 ldb_asprintf_errstring(ldb,
1457                                         "%08X: %s - check_password_restrictions: "
1458                                         "There's no old nt_hash, which is needed "
1459                                         "in order to change your password!",
1460                                         W_ERROR_V(WERR_INVALID_PASSWORD),
1461                                         ldb_strerror(ret));
1462                                 return ret;
1463                         }
1464
1465                         if (memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
1466                                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1467                                 ldb_asprintf_errstring(ldb,
1468                                         "%08X: %s - check_password_restrictions: "
1469                                         "The old password specified doesn't match!",
1470                                         W_ERROR_V(WERR_INVALID_PASSWORD),
1471                                         ldb_strerror(ret));
1472                                 return ret;
1473                         }
1474
1475                         nt_hash_checked = true;
1476                 }
1477
1478                 /* But it is also possible to change a password by the LM hash
1479                  * alone for compatibility reasons. This check is optional if
1480                  * the NT hash was already checked - otherwise it's mandatory.
1481                  * (as the SAMR operations request it). */
1482                 if (io->og.lm_hash) {
1483                         if (!io->o.lm_hash && !nt_hash_checked) {
1484                                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1485                                 ldb_asprintf_errstring(ldb,
1486                                         "%08X: %s - check_password_restrictions: "
1487                                         "There's no old lm_hash, which is needed "
1488                                         "in order to change your password!",
1489                                         W_ERROR_V(WERR_INVALID_PASSWORD),
1490                                         ldb_strerror(ret));
1491                                 return ret;
1492                         }
1493
1494                         if (io->o.lm_hash &&
1495                             memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0) {
1496                                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1497                                 ldb_asprintf_errstring(ldb,
1498                                         "%08X: %s - check_password_restrictions: "
1499                                         "The old password specified doesn't match!",
1500                                         W_ERROR_V(WERR_INVALID_PASSWORD),
1501                                         ldb_strerror(ret));
1502                                 return ret;
1503                         }
1504                 }
1505         }
1506
1507         if (io->u.restrictions == 0) {
1508                 /* FIXME: Is this right? */
1509                 return LDB_SUCCESS;
1510         }
1511
1512         /*
1513          * Fundamental password checks done by the call
1514          * "samdb_check_password".
1515          * It is also in use by "dcesrv_samr_ValidatePassword".
1516          */
1517         if (io->n.cleartext_utf8 != NULL) {
1518                 stat = samdb_check_password(io->n.cleartext_utf8,
1519                                             io->ac->status->domain_data.pwdProperties,
1520                                             io->ac->status->domain_data.minPwdLength);
1521                 switch (stat) {
1522                 case SAMR_VALIDATION_STATUS_SUCCESS:
1523                                 /* perfect -> proceed! */
1524                         break;
1525
1526                 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
1527                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
1528                         ldb_asprintf_errstring(ldb,
1529                                 "%08X: %s - check_password_restrictions: "
1530                                 "the password is too short. It should be equal or longer than %u characters!",
1531                                 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1532                                 ldb_strerror(ret),
1533                                 io->ac->status->domain_data.minPwdLength);
1534                         io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
1535                         return ret;
1536
1537                 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
1538                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
1539                         ldb_asprintf_errstring(ldb,
1540                                 "%08X: %s - check_password_restrictions: "
1541                                 "the password does not meet the complexity criterias!",
1542                                 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1543                                 ldb_strerror(ret));
1544                         io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
1545                         return ret;
1546
1547                 default:
1548                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
1549                         ldb_asprintf_errstring(ldb,
1550                                 "%08X: %s - check_password_restrictions: "
1551                                 "the password doesn't fit by a certain reason!",
1552                                 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1553                                 ldb_strerror(ret));
1554                         return ret;
1555                 }
1556         }
1557
1558         if (io->ac->pwd_reset) {
1559                 return LDB_SUCCESS;
1560         }
1561
1562         if (io->n.nt_hash) {
1563                 uint32_t i;
1564
1565                 /* checks the NT hash password history */
1566                 for (i = 0; i < io->o.nt_history_len; i++) {
1567                         ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
1568                         if (ret == 0) {
1569                                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1570                                 ldb_asprintf_errstring(ldb,
1571                                         "%08X: %s - check_password_restrictions: "
1572                                         "the password was already used (in history)!",
1573                                         W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1574                                         ldb_strerror(ret));
1575                                 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1576                                 return ret;
1577                         }
1578                 }
1579         }
1580
1581         if (io->n.lm_hash) {
1582                 uint32_t i;
1583
1584                 /* checks the LM hash password history */
1585                 for (i = 0; i < io->o.lm_history_len; i++) {
1586                         ret = memcmp(io->n.nt_hash, io->o.lm_history[i].hash, 16);
1587                         if (ret == 0) {
1588                                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1589                                 ldb_asprintf_errstring(ldb,
1590                                         "%08X: %s - check_password_restrictions: "
1591                                         "the password was already used (in history)!",
1592                                         W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1593                                         ldb_strerror(ret));
1594                                 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1595                                 return ret;
1596                         }
1597                 }
1598         }
1599
1600         /* are all password changes disallowed? */
1601         if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1602                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1603                 ldb_asprintf_errstring(ldb,
1604                         "%08X: %s - check_password_restrictions: "
1605                         "password changes disabled!",
1606                         W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1607                         ldb_strerror(ret));
1608                 return ret;
1609         }
1610
1611         /* can this user change the password? */
1612         if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
1613                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1614                 ldb_asprintf_errstring(ldb,
1615                         "%08X: %s - check_password_restrictions: "
1616                         "password can't be changed on this account!",
1617                         W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1618                         ldb_strerror(ret));
1619                 return ret;
1620         }
1621
1622         /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
1623         if (io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) {
1624                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1625                 ldb_asprintf_errstring(ldb,
1626                         "%08X: %s - check_password_restrictions: "
1627                         "password is too young to change!",
1628                         W_ERROR_V(WERR_PASSWORD_RESTRICTION),
1629                         ldb_strerror(ret));
1630                 return ret;
1631         }
1632
1633         return LDB_SUCCESS;
1634 }
1635
1636 static int setup_io(struct ph_context *ac, 
1637                     const struct ldb_message *orig_msg,
1638                     const struct ldb_message *searched_msg, 
1639                     struct setup_password_fields_io *io) 
1640
1641         const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
1642         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1643         struct loadparm_context *lp_ctx =
1644                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1645                                          struct loadparm_context);
1646         int ret;
1647
1648         ZERO_STRUCTP(io);
1649
1650         /* Some operations below require kerberos contexts */
1651
1652         if (smb_krb5_init_context(ac,
1653                                   ldb_get_event_context(ldb),
1654                                   (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
1655                                   &io->smb_krb5_context) != 0) {
1656                 return ldb_operr(ldb);
1657         }
1658
1659         io->ac                          = ac;
1660
1661         io->u.userAccountControl        = ldb_msg_find_attr_as_uint(searched_msg,
1662                                                                     "userAccountControl", 0);
1663         io->u.pwdLastSet                = samdb_result_nttime(searched_msg, "pwdLastSet", 0);
1664         io->u.sAMAccountName            = ldb_msg_find_attr_as_string(searched_msg,
1665                                                                       "sAMAccountName", NULL);
1666         io->u.user_principal_name       = ldb_msg_find_attr_as_string(searched_msg,
1667                                                                       "userPrincipalName", NULL);
1668         io->u.is_computer               = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
1669
1670         if (io->u.sAMAccountName == NULL) {
1671                 ldb_asprintf_errstring(ldb,
1672                                        "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
1673                                        ldb_dn_get_linearized(searched_msg->dn));
1674
1675                 return LDB_ERR_CONSTRAINT_VIOLATION;
1676         }
1677
1678         /* Only non-trust accounts have restrictions (possibly this test is the
1679          * wrong way around, but we like to be restrictive if possible */
1680         io->u.restrictions = !(io->u.userAccountControl
1681                 & (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
1682                         | UF_SERVER_TRUST_ACCOUNT));
1683
1684         if ((io->u.userAccountControl & UF_PASSWD_NOTREQD) != 0) {
1685                 /* see [MS-ADTS] 2.2.15 */
1686                 io->u.restrictions = 0;
1687         }
1688
1689         ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "userPassword",
1690                 &io->n.cleartext_utf8, &io->og.cleartext_utf8);
1691         if (ret != LDB_SUCCESS) {
1692                 ldb_asprintf_errstring(ldb,
1693                         "setup_io: "
1694                         "it's only allowed to set the old password once!");
1695                 return ret;
1696         }
1697
1698         ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "clearTextPassword",
1699                 &io->n.cleartext_utf16, &io->og.cleartext_utf16);
1700         if (ret != LDB_SUCCESS) {
1701                 ldb_asprintf_errstring(ldb,
1702                         "setup_io: "
1703                         "it's only allowed to set the old password once!");
1704                 return ret;
1705         }
1706
1707         /* this rather strange looking piece of code is there to
1708            handle a ldap client setting a password remotely using the
1709            unicodePwd ldap field. The syntax is that the password is
1710            in UTF-16LE, with a " at either end. Unfortunately the
1711            unicodePwd field is also used to store the nt hashes
1712            internally in Samba, and is used in the nt hash format on
1713            the wire in DRS replication, so we have a single name for
1714            two distinct values. The code below leaves us with a small
1715            chance (less than 1 in 2^32) of a mixup, if someone manages
1716            to create a MD4 hash which starts and ends in 0x22 0x00, as
1717            that would then be treated as a UTF16 password rather than
1718            a nthash */
1719
1720         ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "unicodePwd",
1721                 &quoted_utf16, &old_quoted_utf16);
1722         if (ret != LDB_SUCCESS) {
1723                 ldb_asprintf_errstring(ldb,
1724                         "setup_io: "
1725                         "it's only allowed to set the old password once!");
1726                 return ret;
1727         }
1728
1729         /* Checks and converts the actual "unicodePwd" attribute */
1730         if (quoted_utf16 &&
1731             quoted_utf16->length >= 4 &&
1732             quoted_utf16->data[0] == '"' &&
1733             quoted_utf16->data[1] == 0 &&
1734             quoted_utf16->data[quoted_utf16->length-2] == '"' &&
1735             quoted_utf16->data[quoted_utf16->length-1] == 0) {
1736                 struct ldb_val *quoted_utf16_2;
1737
1738                 if (io->n.cleartext_utf16) {
1739                         /* refuse the change if someone wants to change with
1740                            with both UTF16 possibilities at the same time... */
1741                         ldb_asprintf_errstring(ldb,
1742                                 "setup_io: "
1743                                 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
1744                         return LDB_ERR_UNWILLING_TO_PERFORM;
1745                 }
1746
1747                 /*
1748                  * adapt the quoted UTF16 string to be a real
1749                  * cleartext one
1750                  */
1751                 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
1752                 if (quoted_utf16_2 == NULL) {
1753                         return ldb_oom(ldb);
1754                 }
1755
1756                 quoted_utf16_2->data = quoted_utf16->data + 2;
1757                 quoted_utf16_2->length = quoted_utf16->length-4;
1758                 io->n.cleartext_utf16 = quoted_utf16_2;
1759                 io->n.nt_hash = NULL;
1760
1761         } else if (quoted_utf16) {
1762                 /* We have only the hash available -> so no plaintext here */
1763                 if (!ac->hash_values) {
1764                         /* refuse the change if someone wants to change
1765                            the hash without control specified... */
1766                         ldb_asprintf_errstring(ldb,
1767                                 "setup_io: "
1768                                 "it's not allowed to set the NT hash password directly'");
1769                         /* this looks odd but this is what Windows does:
1770                            returns "UNWILLING_TO_PERFORM" on wrong
1771                            password sets and "CONSTRAINT_VIOLATION" on
1772                            wrong password changes. */
1773                         if (old_quoted_utf16 == NULL) {
1774                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1775                         }
1776
1777                         return LDB_ERR_CONSTRAINT_VIOLATION;
1778                 }
1779
1780                 io->n.nt_hash = talloc(io->ac, struct samr_Password);
1781                 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
1782                        MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
1783         }
1784
1785         /* Checks and converts the previous "unicodePwd" attribute */
1786         if (old_quoted_utf16 &&
1787             old_quoted_utf16->length >= 4 &&
1788             old_quoted_utf16->data[0] == '"' &&
1789             old_quoted_utf16->data[1] == 0 &&
1790             old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
1791             old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
1792                 struct ldb_val *old_quoted_utf16_2;
1793
1794                 if (io->og.cleartext_utf16) {
1795                         /* refuse the change if someone wants to change with
1796                            both UTF16 possibilities at the same time... */
1797                         ldb_asprintf_errstring(ldb,
1798                                 "setup_io: "
1799                                 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
1800                         return LDB_ERR_UNWILLING_TO_PERFORM;
1801                 }
1802
1803                 /*
1804                  * adapt the quoted UTF16 string to be a real
1805                  * cleartext one
1806                  */
1807                 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
1808                 if (old_quoted_utf16_2 == NULL) {
1809                         return ldb_oom(ldb);
1810                 }
1811
1812                 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
1813                 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
1814
1815                 io->og.cleartext_utf16 = old_quoted_utf16_2;
1816                 io->og.nt_hash = NULL;
1817         } else if (old_quoted_utf16) {
1818                 /* We have only the hash available -> so no plaintext here */
1819                 if (!ac->hash_values) {
1820                         /* refuse the change if someone wants to change
1821                            the hash without control specified... */
1822                         ldb_asprintf_errstring(ldb,
1823                                 "setup_io: "
1824                                 "it's not allowed to set the NT hash password directly'");
1825                         return LDB_ERR_UNWILLING_TO_PERFORM;
1826                 }
1827
1828                 io->og.nt_hash = talloc(io->ac, struct samr_Password);
1829                 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
1830                        MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
1831         }
1832
1833         /* Handles the "dBCSPwd" attribute (LM hash) */
1834         io->n.lm_hash = NULL; io->og.lm_hash = NULL;
1835         ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "dBCSPwd",
1836                 &lm_hash, &old_lm_hash);
1837         if (ret != LDB_SUCCESS) {
1838                 ldb_asprintf_errstring(ldb,
1839                         "setup_io: "
1840                         "it's only allowed to set the old password once!");
1841                 return ret;
1842         }
1843
1844         if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
1845                 /* refuse the change if someone wants to change the hash
1846                    without control specified... */
1847                 ldb_asprintf_errstring(ldb,
1848                         "setup_io: "
1849                         "it's not allowed to set the LM hash password directly'");
1850                 return LDB_ERR_UNWILLING_TO_PERFORM;
1851         }
1852
1853         if (lpcfg_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
1854                 io->n.lm_hash = talloc(io->ac, struct samr_Password);
1855                 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
1856                        sizeof(io->n.lm_hash->hash)));
1857         }
1858         if (lpcfg_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
1859                 io->og.lm_hash = talloc(io->ac, struct samr_Password);
1860                 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
1861                        sizeof(io->og.lm_hash->hash)));
1862         }
1863
1864         /*
1865          * Handles the password change control if it's specified. It has the
1866          * precedance and overrides already specified old password values of
1867          * change requests (but that shouldn't happen since the control is
1868          * fully internal and only used in conjunction with replace requests!).
1869          */
1870         if (ac->change != NULL) {
1871                 io->og.nt_hash = NULL;
1872                 if (ac->change->old_nt_pwd_hash != NULL) {
1873                         io->og.nt_hash = talloc_memdup(io->ac,
1874                                                        ac->change->old_nt_pwd_hash,
1875                                                        sizeof(struct samr_Password));
1876                 }
1877                 io->og.lm_hash = NULL;
1878                 if (lpcfg_lanman_auth(lp_ctx) && (ac->change->old_lm_pwd_hash != NULL)) {
1879                         io->og.lm_hash = talloc_memdup(io->ac,
1880                                                        ac->change->old_lm_pwd_hash,
1881                                                        sizeof(struct samr_Password));
1882                 }
1883         }
1884
1885         /* refuse the change if someone wants to change the clear-
1886            text and supply his own hashes at the same time... */
1887         if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
1888                         && (io->n.nt_hash || io->n.lm_hash)) {
1889                 ldb_asprintf_errstring(ldb,
1890                         "setup_io: "
1891                         "it's only allowed to set the password in form of cleartext attributes or as hashes");
1892                 return LDB_ERR_UNWILLING_TO_PERFORM;
1893         }
1894
1895         /* refuse the change if someone wants to change the password
1896            using both plaintext methods (UTF8 and UTF16) at the same time... */
1897         if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
1898                 ldb_asprintf_errstring(ldb,
1899                         "setup_io: "
1900                         "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
1901                 return LDB_ERR_UNWILLING_TO_PERFORM;
1902         }
1903
1904         /* refuse the change if someone tries to set/change the password by
1905          * the lanman hash alone and we've deactivated that mechanism. This
1906          * would end in an account without any password! */
1907         if ((!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
1908             && (!io->n.nt_hash) && (!io->n.lm_hash)) {
1909                 ldb_asprintf_errstring(ldb,
1910                         "setup_io: "
1911                         "The password change/set operations performed using the LAN Manager hash alone are deactivated!");
1912                 return LDB_ERR_UNWILLING_TO_PERFORM;
1913         }
1914
1915         /* refuse the change if someone wants to compare against a plaintext
1916            or hash at the same time for a "password modify" operation... */
1917         if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
1918             && (io->og.nt_hash || io->og.lm_hash)) {
1919                 ldb_asprintf_errstring(ldb,
1920                         "setup_io: "
1921                         "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
1922                 return LDB_ERR_UNWILLING_TO_PERFORM;
1923         }
1924
1925         /* refuse the change if someone wants to compare against both
1926          * plaintexts at the same time for a "password modify" operation... */
1927         if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
1928                 ldb_asprintf_errstring(ldb,
1929                         "setup_io: "
1930                         "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
1931                 return LDB_ERR_UNWILLING_TO_PERFORM;
1932         }
1933
1934         /* Decides if we have a password modify or password reset operation */
1935         if (ac->req->operation == LDB_ADD) {
1936                 /* On "add" we have only "password reset" */
1937                 ac->pwd_reset = true;
1938         } else if (ac->req->operation == LDB_MODIFY) {
1939                 if (io->og.cleartext_utf8 || io->og.cleartext_utf16
1940                     || io->og.nt_hash || io->og.lm_hash) {
1941                         /* If we have an old password specified then for sure it
1942                          * is a user "password change" */
1943                         ac->pwd_reset = false;
1944                 } else {
1945                         /* Otherwise we have also here a "password reset" */
1946                         ac->pwd_reset = true;
1947                 }
1948         } else {
1949                 /* this shouldn't happen */
1950                 return ldb_operr(ldb);
1951         }
1952
1953         return LDB_SUCCESS;
1954 }
1955
1956 static struct ph_context *ph_init_context(struct ldb_module *module,
1957                                           struct ldb_request *req)
1958 {
1959         struct ldb_context *ldb;
1960         struct ph_context *ac;
1961
1962         ldb = ldb_module_get_ctx(module);
1963
1964         ac = talloc_zero(req, struct ph_context);
1965         if (ac == NULL) {
1966                 ldb_set_errstring(ldb, "Out of Memory");
1967                 return NULL;
1968         }
1969
1970         ac->module = module;
1971         ac->req = req;
1972
1973         return ac;
1974 }
1975
1976 static void ph_apply_controls(struct ph_context *ac)
1977 {
1978         struct ldb_control *ctrl;
1979
1980         ac->change_status = false;
1981         ctrl = ldb_request_get_control(ac->req,
1982                                        DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
1983         if (ctrl != NULL) {
1984                 ac->change_status = true;
1985
1986                 /* Mark the "change status" control as uncritical (done) */
1987                 ctrl->critical = false;
1988         }
1989
1990         ac->hash_values = false;
1991         ctrl = ldb_request_get_control(ac->req,
1992                                        DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
1993         if (ctrl != NULL) {
1994                 ac->hash_values = true;
1995
1996                 /* Mark the "hash values" control as uncritical (done) */
1997                 ctrl->critical = false;
1998         }
1999
2000         ctrl = ldb_request_get_control(ac->req,
2001                                        DSDB_CONTROL_PASSWORD_CHANGE_OID);
2002         if (ctrl != NULL) {
2003                 ac->change = (struct dsdb_control_password_change *) ctrl->data;
2004
2005                 /* Mark the "change" control as uncritical (done) */
2006                 ctrl->critical = false;
2007         }
2008 }
2009
2010 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
2011 {
2012         struct ph_context *ac;
2013
2014         ac = talloc_get_type(req->context, struct ph_context);
2015
2016         if (!ares) {
2017                 return ldb_module_done(ac->req, NULL, NULL,
2018                                         LDB_ERR_OPERATIONS_ERROR);
2019         }
2020
2021         if (ares->type == LDB_REPLY_REFERRAL) {
2022                 return ldb_module_send_referral(ac->req, ares->referral);
2023         }
2024
2025         if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2026                 /* On success and trivial errors a status control is being
2027                  * added (used for example by the "samdb_set_password" call) */
2028                 ldb_reply_add_control(ares,
2029                                       DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2030                                       false,
2031                                       ac->status);
2032         }
2033
2034         if (ares->error != LDB_SUCCESS) {
2035                 return ldb_module_done(ac->req, ares->controls,
2036                                         ares->response, ares->error);
2037         }
2038
2039         if (ares->type != LDB_REPLY_DONE) {
2040                 talloc_free(ares);
2041                 return ldb_module_done(ac->req, NULL, NULL,
2042                                         LDB_ERR_OPERATIONS_ERROR);
2043         }
2044
2045         return ldb_module_done(ac->req, ares->controls,
2046                                 ares->response, ares->error);
2047 }
2048
2049 static int password_hash_add_do_add(struct ph_context *ac);
2050 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
2051 static int password_hash_mod_search_self(struct ph_context *ac);
2052 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
2053 static int password_hash_mod_do_mod(struct ph_context *ac);
2054
2055 static int get_domain_data_callback(struct ldb_request *req,
2056                                     struct ldb_reply *ares)
2057 {
2058         struct ldb_context *ldb;
2059         struct ph_context *ac;
2060         struct loadparm_context *lp_ctx;
2061         int ret;
2062
2063         ac = talloc_get_type(req->context, struct ph_context);
2064         ldb = ldb_module_get_ctx(ac->module);
2065
2066         if (!ares) {
2067                 ret = LDB_ERR_OPERATIONS_ERROR;
2068                 goto done;
2069         }
2070         if (ares->error != LDB_SUCCESS) {
2071                 return ldb_module_done(ac->req, ares->controls,
2072                                         ares->response, ares->error);
2073         }
2074
2075         switch (ares->type) {
2076         case LDB_REPLY_ENTRY:
2077                 if (ac->status != NULL) {
2078                         talloc_free(ares);
2079
2080                         ldb_set_errstring(ldb, "Too many results");
2081                         ret = LDB_ERR_OPERATIONS_ERROR;
2082                         goto done;
2083                 }
2084
2085                 /* Setup the "status" structure (used as control later) */
2086                 ac->status = talloc_zero(ac->req,
2087                                          struct dsdb_control_password_change_status);
2088                 if (ac->status == NULL) {
2089                         talloc_free(ares);
2090
2091                         ldb_oom(ldb);
2092                         ret = LDB_ERR_OPERATIONS_ERROR;
2093                         goto done;
2094                 }
2095
2096                 /* Setup the "domain data" structure */
2097                 ac->status->domain_data.pwdProperties =
2098                         ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
2099                 ac->status->domain_data.pwdHistoryLength =
2100                         ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
2101                 ac->status->domain_data.maxPwdAge =
2102                         ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
2103                 ac->status->domain_data.minPwdAge =
2104                         ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
2105                 ac->status->domain_data.minPwdLength =
2106                         ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
2107                 ac->status->domain_data.store_cleartext =
2108                         ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
2109
2110                 talloc_free(ares);
2111
2112                 /* For a domain DN, this puts things in dotted notation */
2113                 /* For builtin domains, this will give details for the host,
2114                  * but that doesn't really matter, as it's just used for salt
2115                  * and kerberos principals, which don't exist here */
2116
2117                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2118                                          struct loadparm_context);
2119
2120                 ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
2121                 ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
2122                 ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
2123
2124                 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2125
2126                 ret = LDB_SUCCESS;
2127                 break;
2128
2129         case LDB_REPLY_REFERRAL:
2130                 /* ignore */
2131                 talloc_free(ares);
2132                 ret = LDB_SUCCESS;
2133                 break;
2134
2135         case LDB_REPLY_DONE:
2136                 talloc_free(ares);
2137                 /* call the next step */
2138                 switch (ac->req->operation) {
2139                 case LDB_ADD:
2140                         ret = password_hash_add_do_add(ac);
2141                         break;
2142
2143                 case LDB_MODIFY:
2144                         ret = password_hash_mod_do_mod(ac);
2145                         break;
2146
2147                 default:
2148                         ret = LDB_ERR_OPERATIONS_ERROR;
2149                         break;
2150                 }
2151                 break;
2152         }
2153
2154 done:
2155         if (ret != LDB_SUCCESS) {
2156                 struct ldb_reply *new_ares;
2157
2158                 new_ares = talloc_zero(ac->req, struct ldb_reply);
2159                 if (new_ares == NULL) {
2160                         ldb_oom(ldb);
2161                         return ldb_module_done(ac->req, NULL, NULL,
2162                                                LDB_ERR_OPERATIONS_ERROR);
2163                 }
2164
2165                 new_ares->error = ret;
2166                 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2167                         /* On success and trivial errors a status control is being
2168                          * added (used for example by the "samdb_set_password" call) */
2169                         ldb_reply_add_control(new_ares,
2170                                               DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2171                                               false,
2172                                               ac->status);
2173                 }
2174
2175                 return ldb_module_done(ac->req, new_ares->controls,
2176                                        new_ares->response, new_ares->error);
2177         }
2178
2179         return LDB_SUCCESS;
2180 }
2181
2182 static int build_domain_data_request(struct ph_context *ac)
2183 {
2184         /* attrs[] is returned from this function in
2185            ac->dom_req->op.search.attrs, so it must be static, as
2186            otherwise the compiler can put it on the stack */
2187         struct ldb_context *ldb;
2188         static const char * const attrs[] = { "pwdProperties",
2189                                               "pwdHistoryLength",
2190                                               "maxPwdAge",
2191                                               "minPwdAge",
2192                                               "minPwdLength",
2193                                               NULL };
2194         int ret;
2195
2196         ldb = ldb_module_get_ctx(ac->module);
2197
2198         ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
2199                                    ldb_get_default_basedn(ldb),
2200                                    LDB_SCOPE_BASE,
2201                                    NULL, attrs,
2202                                    NULL,
2203                                    ac, get_domain_data_callback,
2204                                    ac->req);
2205         LDB_REQ_SET_LOCATION(ac->dom_req);
2206         return ret;
2207 }
2208
2209 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
2210 {
2211         struct ldb_context *ldb;
2212         struct ph_context *ac;
2213         struct ldb_message_element *userPasswordAttr, *clearTextPasswordAttr,
2214                 *ntAttr, *lmAttr;
2215         int ret;
2216         struct ldb_control *bypass = NULL;
2217
2218         ldb = ldb_module_get_ctx(module);
2219
2220         ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
2221
2222         if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
2223                 return ldb_next_request(module, req);
2224         }
2225
2226         /* If the caller is manipulating the local passwords directly, let them pass */
2227         if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
2228                                 req->op.add.message->dn) == 0) {
2229                 return ldb_next_request(module, req);
2230         }
2231
2232         bypass = ldb_request_get_control(req,
2233                                          DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
2234         if (bypass != NULL) {
2235                 /* Mark the "bypass" control as uncritical (done) */
2236                 bypass->critical = false;
2237                 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add (bypassing)\n");
2238                 return ldb_next_request(module, req);
2239         }
2240
2241         /* nobody must touch password histories and 'supplementalCredentials' */
2242         if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
2243                 return LDB_ERR_UNWILLING_TO_PERFORM;
2244         }
2245         if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
2246                 return LDB_ERR_UNWILLING_TO_PERFORM;
2247         }
2248         if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
2249                 return LDB_ERR_UNWILLING_TO_PERFORM;
2250         }
2251
2252         /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
2253          * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes. */
2254
2255         userPasswordAttr = ldb_msg_find_element(req->op.add.message, "userPassword");
2256         clearTextPasswordAttr = ldb_msg_find_element(req->op.add.message, "clearTextPassword");
2257         ntAttr = ldb_msg_find_element(req->op.add.message, "unicodePwd");
2258         lmAttr = ldb_msg_find_element(req->op.add.message, "dBCSPwd");
2259
2260         if ((!userPasswordAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
2261                 return ldb_next_request(module, req);
2262         }
2263
2264         /* Make sure we are performing the password set action on a (for us)
2265          * valid object. Those are instances of either "user" and/or
2266          * "inetOrgPerson". Otherwise continue with the submodules. */
2267         if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
2268                 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
2269
2270                 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
2271                         ldb_set_errstring(ldb,
2272                                           "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
2273                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
2274                 }
2275
2276                 return ldb_next_request(module, req);
2277         }
2278
2279         ac = ph_init_context(module, req);
2280         if (ac == NULL) {
2281                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
2282                 return ldb_operr(ldb);
2283         }
2284         ph_apply_controls(ac);
2285
2286         /* get user domain data */
2287         ret = build_domain_data_request(ac);
2288         if (ret != LDB_SUCCESS) {
2289                 return ret;
2290         }
2291
2292         return ldb_next_request(module, ac->dom_req);
2293 }
2294
2295 static int password_hash_add_do_add(struct ph_context *ac)
2296 {
2297         struct ldb_context *ldb;
2298         struct ldb_request *down_req;
2299         struct ldb_message *msg;
2300         struct setup_password_fields_io io;
2301         int ret;
2302
2303         /* Prepare the internal data structure containing the passwords */
2304         ret = setup_io(ac, ac->req->op.add.message, ac->req->op.add.message, &io);
2305         if (ret != LDB_SUCCESS) {
2306                 return ret;
2307         }
2308
2309         ldb = ldb_module_get_ctx(ac->module);
2310
2311         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
2312         if (msg == NULL) {
2313                 return ldb_operr(ldb);
2314         }
2315
2316         /* remove attributes that we just read into 'io' */
2317         ldb_msg_remove_attr(msg, "userPassword");
2318         ldb_msg_remove_attr(msg, "clearTextPassword");
2319         ldb_msg_remove_attr(msg, "unicodePwd");
2320         ldb_msg_remove_attr(msg, "dBCSPwd");
2321         ldb_msg_remove_attr(msg, "pwdLastSet");
2322
2323         ret = setup_password_fields(&io);
2324         if (ret != LDB_SUCCESS) {
2325                 return ret;
2326         }
2327
2328         ret = check_password_restrictions(&io);
2329         if (ret != LDB_SUCCESS) {
2330                 return ret;
2331         }
2332
2333         if (io.g.nt_hash) {
2334                 ret = samdb_msg_add_hash(ldb, ac, msg,
2335                                          "unicodePwd", io.g.nt_hash);
2336                 if (ret != LDB_SUCCESS) {
2337                         return ret;
2338                 }
2339         }
2340         if (io.g.lm_hash) {
2341                 ret = samdb_msg_add_hash(ldb, ac, msg,
2342                                          "dBCSPwd", io.g.lm_hash);
2343                 if (ret != LDB_SUCCESS) {
2344                         return ret;
2345                 }
2346         }
2347         if (io.g.nt_history_len > 0) {
2348                 ret = samdb_msg_add_hashes(ldb, ac, msg,
2349                                            "ntPwdHistory",
2350                                            io.g.nt_history,
2351                                            io.g.nt_history_len);
2352                 if (ret != LDB_SUCCESS) {
2353                         return ret;
2354                 }
2355         }
2356         if (io.g.lm_history_len > 0) {
2357                 ret = samdb_msg_add_hashes(ldb, ac, msg,
2358                                            "lmPwdHistory",
2359                                            io.g.lm_history,
2360                                            io.g.lm_history_len);
2361                 if (ret != LDB_SUCCESS) {
2362                         return ret;
2363                 }
2364         }
2365         if (io.g.supplemental.length > 0) {
2366                 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2367                                         &io.g.supplemental, NULL);
2368                 if (ret != LDB_SUCCESS) {
2369                         return ret;
2370                 }
2371         }
2372         ret = samdb_msg_add_uint64(ldb, ac, msg,
2373                                    "pwdLastSet",
2374                                    io.g.last_set);
2375         if (ret != LDB_SUCCESS) {
2376                 return ret;
2377         }
2378
2379         ret = ldb_build_add_req(&down_req, ldb, ac,
2380                                 msg,
2381                                 ac->req->controls,
2382                                 ac, ph_op_callback,
2383                                 ac->req);
2384         LDB_REQ_SET_LOCATION(down_req);
2385         if (ret != LDB_SUCCESS) {
2386                 return ret;
2387         }
2388
2389         return ldb_next_request(ac->module, down_req);
2390 }
2391
2392 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
2393 {
2394         struct ldb_context *ldb;
2395         struct ph_context *ac;
2396         const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
2397                 "unicodePwd", "dBCSPwd", NULL }, **l;
2398         unsigned int attr_cnt, del_attr_cnt, add_attr_cnt, rep_attr_cnt;
2399         struct ldb_message_element *passwordAttr;
2400         struct ldb_message *msg;
2401         struct ldb_request *down_req;
2402         int ret;
2403         struct ldb_control *bypass = NULL;
2404
2405         ldb = ldb_module_get_ctx(module);
2406
2407         ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
2408
2409         if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
2410                 return ldb_next_request(module, req);
2411         }
2412         
2413         /* If the caller is manipulating the local passwords directly, let them pass */
2414         if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
2415                                 req->op.mod.message->dn) == 0) {
2416                 return ldb_next_request(module, req);
2417         }
2418
2419         bypass = ldb_request_get_control(req,
2420                                          DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
2421         if (bypass != NULL) {
2422                 /* Mark the "bypass" control as uncritical (done) */
2423                 bypass->critical = false;
2424                 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify (bypassing)\n");
2425                 return ldb_next_request(module, req);
2426         }
2427
2428         /* nobody must touch password histories and 'supplementalCredentials' */
2429         if (ldb_msg_find_element(req->op.mod.message, "ntPwdHistory")) {
2430                 return LDB_ERR_UNWILLING_TO_PERFORM;
2431         }
2432         if (ldb_msg_find_element(req->op.mod.message, "lmPwdHistory")) {
2433                 return LDB_ERR_UNWILLING_TO_PERFORM;
2434         }
2435         if (ldb_msg_find_element(req->op.mod.message, "supplementalCredentials")) {
2436                 return LDB_ERR_UNWILLING_TO_PERFORM;
2437         }
2438
2439         /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
2440          * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
2441          * For password changes/set there should be a 'delete' or a 'modify'
2442          * on these attributes. */
2443         attr_cnt = 0;
2444         for (l = passwordAttrs; *l != NULL; l++) {
2445                 if (ldb_msg_find_element(req->op.mod.message, *l) != NULL) {
2446                         ++attr_cnt;
2447                 }
2448         }
2449         if (attr_cnt == 0) {
2450                 return ldb_next_request(module, req);
2451         }
2452
2453         ac = ph_init_context(module, req);
2454         if (!ac) {
2455                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
2456                 return ldb_operr(ldb);
2457         }
2458         ph_apply_controls(ac);
2459
2460         /* use a new message structure so that we can modify it */
2461         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2462         if (msg == NULL) {
2463                 return ldb_oom(ldb);
2464         }
2465
2466         /* - check for single-valued password attributes
2467          *   (if not return "CONSTRAINT_VIOLATION")
2468          * - check that for a password change operation one add and one delete
2469          *   operation exists
2470          *   (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
2471          * - check that a password change and a password set operation cannot
2472          *   be mixed
2473          *   (if not return "UNWILLING_TO_PERFORM")
2474          * - remove all password attributes modifications from the first change
2475          *   operation (anything without the passwords) - we will make the real
2476          *   modification later */
2477         del_attr_cnt = 0;
2478         add_attr_cnt = 0;
2479         rep_attr_cnt = 0;
2480         for (l = passwordAttrs; *l != NULL; l++) {
2481                 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
2482                         if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE) {
2483                                 ++del_attr_cnt;
2484                         }
2485                         if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD) {
2486                                 ++add_attr_cnt;
2487                         }
2488                         if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_REPLACE) {
2489                                 ++rep_attr_cnt;
2490                         }
2491                         if ((passwordAttr->num_values != 1) &&
2492                             (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD)) {
2493                                 talloc_free(ac);
2494                                 ldb_asprintf_errstring(ldb,
2495                                                        "'%s' attribute must have exactly one value on add operations!",
2496                                                        *l);
2497                                 return LDB_ERR_CONSTRAINT_VIOLATION;
2498                         }
2499                         if ((passwordAttr->num_values > 1) &&
2500                             (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE)) {
2501                                 talloc_free(ac);
2502                                 ldb_asprintf_errstring(ldb,
2503                                                        "'%s' attribute must have zero or one value(s) on delete operations!",
2504                                                        *l);
2505                                 return LDB_ERR_CONSTRAINT_VIOLATION;
2506                         }
2507                         ldb_msg_remove_element(msg, passwordAttr);
2508                 }
2509         }
2510         if ((del_attr_cnt > 0) && (add_attr_cnt == 0)) {
2511                 talloc_free(ac);
2512                 ldb_set_errstring(ldb,
2513                                   "Only the delete action for a password change specified!");
2514                 return LDB_ERR_CONSTRAINT_VIOLATION;
2515         }
2516         if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
2517                 talloc_free(ac);
2518                 ldb_set_errstring(ldb,
2519                                   "Only the add action for a password change specified!");
2520                 return LDB_ERR_UNWILLING_TO_PERFORM;
2521         }
2522         if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
2523                 talloc_free(ac);
2524                 ldb_set_errstring(ldb,
2525                                   "Only one delete and one add action for a password change allowed!");
2526                 return LDB_ERR_UNWILLING_TO_PERFORM;
2527         }
2528         if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
2529                 talloc_free(ac);
2530                 ldb_set_errstring(ldb,
2531                                   "Either a password change or a password set operation is allowed!");
2532                 return LDB_ERR_UNWILLING_TO_PERFORM;
2533         }
2534
2535         /* if there was nothing else to be modified skip to next step */
2536         if (msg->num_elements == 0) {
2537                 return password_hash_mod_search_self(ac);
2538         }
2539
2540         ret = ldb_build_mod_req(&down_req, ldb, ac,
2541                                 msg,
2542                                 req->controls,
2543                                 ac, ph_modify_callback,
2544                                 req);
2545         LDB_REQ_SET_LOCATION(down_req);
2546         if (ret != LDB_SUCCESS) {
2547                 return ret;
2548         }
2549
2550         return ldb_next_request(module, down_req);
2551 }
2552
2553 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
2554 {
2555         struct ph_context *ac;
2556
2557         ac = talloc_get_type(req->context, struct ph_context);
2558
2559         if (!ares) {
2560                 return ldb_module_done(ac->req, NULL, NULL,
2561                                         LDB_ERR_OPERATIONS_ERROR);
2562         }
2563
2564         if (ares->type == LDB_REPLY_REFERRAL) {
2565                 return ldb_module_send_referral(ac->req, ares->referral);
2566         }
2567
2568         if (ares->error != LDB_SUCCESS) {
2569                 return ldb_module_done(ac->req, ares->controls,
2570                                         ares->response, ares->error);
2571         }
2572
2573         if (ares->type != LDB_REPLY_DONE) {
2574                 talloc_free(ares);
2575                 return ldb_module_done(ac->req, NULL, NULL,
2576                                         LDB_ERR_OPERATIONS_ERROR);
2577         }
2578
2579         talloc_free(ares);
2580
2581         return password_hash_mod_search_self(ac);
2582 }
2583
2584 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
2585 {
2586         struct ldb_context *ldb;
2587         struct ph_context *ac;
2588         int ret;
2589
2590         ac = talloc_get_type(req->context, struct ph_context);
2591         ldb = ldb_module_get_ctx(ac->module);
2592
2593         if (!ares) {
2594                 ret = LDB_ERR_OPERATIONS_ERROR;
2595                 goto done;
2596         }
2597         if (ares->error != LDB_SUCCESS) {
2598                 return ldb_module_done(ac->req, ares->controls,
2599                                         ares->response, ares->error);
2600         }
2601
2602         /* we are interested only in the single reply (base search) */
2603         switch (ares->type) {
2604         case LDB_REPLY_ENTRY:
2605                 /* Make sure we are performing the password change action on a
2606                  * (for us) valid object. Those are instances of either "user"
2607                  * and/or "inetOrgPerson". Otherwise continue with the
2608                  * submodules. */
2609                 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
2610                         && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
2611                         talloc_free(ares);
2612
2613                         if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
2614                                 ldb_set_errstring(ldb,
2615                                                   "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
2616                                 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
2617                                 goto done;
2618                         }
2619
2620                         ret = ldb_next_request(ac->module, ac->req);
2621                         goto done;
2622                 }
2623
2624                 if (ac->search_res != NULL) {
2625                         talloc_free(ares);
2626
2627                         ldb_set_errstring(ldb, "Too many results");
2628                         ret = LDB_ERR_OPERATIONS_ERROR;
2629                         goto done;
2630                 }
2631
2632                 ac->search_res = talloc_steal(ac, ares);
2633                 ret = LDB_SUCCESS;
2634                 break;
2635
2636         case LDB_REPLY_REFERRAL:
2637                 /* ignore anything else for now */
2638                 talloc_free(ares);
2639                 ret = LDB_SUCCESS;
2640                 break;
2641
2642         case LDB_REPLY_DONE:
2643                 talloc_free(ares);
2644
2645                 /* get user domain data */
2646                 ret = build_domain_data_request(ac);
2647                 if (ret != LDB_SUCCESS) {
2648                         return ldb_module_done(ac->req, NULL, NULL, ret);
2649                 }
2650
2651                 ret = ldb_next_request(ac->module, ac->dom_req);
2652                 break;
2653         }
2654
2655 done:
2656         if (ret != LDB_SUCCESS) {
2657                 return ldb_module_done(ac->req, NULL, NULL, ret);
2658         }
2659
2660         return LDB_SUCCESS;
2661 }
2662
2663 static int password_hash_mod_search_self(struct ph_context *ac)
2664 {
2665         struct ldb_context *ldb;
2666         static const char * const attrs[] = { "objectClass",
2667                                               "userAccountControl",
2668                                               "pwdLastSet",
2669                                               "sAMAccountName",
2670                                               "objectSid",
2671                                               "userPrincipalName",
2672                                               "supplementalCredentials",
2673                                               "lmPwdHistory",
2674                                               "ntPwdHistory",
2675                                               "dBCSPwd",
2676                                               "unicodePwd",
2677                                               NULL };
2678         struct ldb_request *search_req;
2679         int ret;
2680
2681         ldb = ldb_module_get_ctx(ac->module);
2682
2683         ret = ldb_build_search_req(&search_req, ldb, ac,
2684                                    ac->req->op.mod.message->dn,
2685                                    LDB_SCOPE_BASE,
2686                                    "(objectclass=*)",
2687                                    attrs,
2688                                    NULL,
2689                                    ac, ph_mod_search_callback,
2690                                    ac->req);
2691         LDB_REQ_SET_LOCATION(search_req);
2692         if (ret != LDB_SUCCESS) {
2693                 return ret;
2694         }
2695
2696         return ldb_next_request(ac->module, search_req);
2697 }
2698
2699 static int password_hash_mod_do_mod(struct ph_context *ac)
2700 {
2701         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2702         struct loadparm_context *lp_ctx =
2703                                 talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2704                                                 struct loadparm_context);
2705         struct ldb_request *mod_req;
2706         struct ldb_message *msg;
2707         const struct ldb_message *orig_msg, *searched_msg;
2708         struct setup_password_fields_io io;
2709         int ret;
2710         NTSTATUS status;
2711
2712         /* use a new message structure so that we can modify it */
2713         msg = ldb_msg_new(ac);
2714         if (msg == NULL) {
2715                 return ldb_operr(ldb);
2716         }
2717
2718         /* modify dn */
2719         msg->dn = ac->req->op.mod.message->dn;
2720
2721         orig_msg = ac->req->op.mod.message;
2722         searched_msg = ac->search_res->message;
2723
2724         /* Prepare the internal data structure containing the passwords */
2725         ret = setup_io(ac, orig_msg, searched_msg, &io);
2726         if (ret != LDB_SUCCESS) {
2727                 return ret;
2728         }
2729         
2730         /* Get the old password from the database */
2731         status = samdb_result_passwords(io.ac,
2732                                         lp_ctx,
2733                                         discard_const_p(struct ldb_message, searched_msg),
2734                                         &io.o.lm_hash, &io.o.nt_hash);
2735         if (!NT_STATUS_IS_OK(status)) {
2736                 return ldb_operr(ldb);
2737         }
2738
2739         io.o.nt_history_len             = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
2740         io.o.lm_history_len             = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
2741         io.o.supplemental               = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
2742
2743         ret = setup_password_fields(&io);
2744         if (ret != LDB_SUCCESS) {
2745                 return ret;
2746         }
2747
2748         ret = check_password_restrictions(&io);
2749         if (ret != LDB_SUCCESS) {
2750                 return ret;
2751         }
2752
2753         /* make sure we replace all the old attributes */
2754         ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
2755         ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
2756         ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2757         ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2758         ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
2759         ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
2760
2761         if (io.g.nt_hash) {
2762                 ret = samdb_msg_add_hash(ldb, ac, msg,
2763                                          "unicodePwd", io.g.nt_hash);
2764                 if (ret != LDB_SUCCESS) {
2765                         return ret;
2766                 }
2767         }
2768         if (io.g.lm_hash) {
2769                 ret = samdb_msg_add_hash(ldb, ac, msg,
2770                                          "dBCSPwd", io.g.lm_hash);
2771                 if (ret != LDB_SUCCESS) {
2772                         return ret;
2773                 }
2774         }
2775         if (io.g.nt_history_len > 0) {
2776                 ret = samdb_msg_add_hashes(ldb, ac, msg,
2777                                            "ntPwdHistory",
2778                                            io.g.nt_history,
2779                                            io.g.nt_history_len);
2780                 if (ret != LDB_SUCCESS) {
2781                         return ret;
2782                 }
2783         }
2784         if (io.g.lm_history_len > 0) {
2785                 ret = samdb_msg_add_hashes(ldb, ac, msg,
2786                                            "lmPwdHistory",
2787                                            io.g.lm_history,
2788                                            io.g.lm_history_len);
2789                 if (ret != LDB_SUCCESS) {
2790                         return ret;
2791                 }
2792         }
2793         if (io.g.supplemental.length > 0) {
2794                 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2795                                         &io.g.supplemental, NULL);
2796                 if (ret != LDB_SUCCESS) {
2797                         return ret;
2798                 }
2799         }
2800         ret = samdb_msg_add_uint64(ldb, ac, msg,
2801                                    "pwdLastSet",
2802                                    io.g.last_set);
2803         if (ret != LDB_SUCCESS) {
2804                 return ret;
2805         }
2806
2807         ret = ldb_build_mod_req(&mod_req, ldb, ac,
2808                                 msg,
2809                                 ac->req->controls,
2810                                 ac, ph_op_callback,
2811                                 ac->req);
2812         LDB_REQ_SET_LOCATION(mod_req);
2813         if (ret != LDB_SUCCESS) {
2814                 return ret;
2815         }
2816
2817         return ldb_next_request(ac->module, mod_req);
2818 }
2819
2820 static const struct ldb_module_ops ldb_password_hash_module_ops = {
2821         .name          = "password_hash",
2822         .add           = password_hash_add,
2823         .modify        = password_hash_modify
2824 };
2825
2826 int ldb_password_hash_module_init(const char *version)
2827 {
2828         LDB_MODULE_CHECK_VERSION(version);
2829         return ldb_register_module(&ldb_password_hash_module_ops);
2830 }