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