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