password_hash: fix the callers after drsblobs.idl changes
[samba.git] / source4 / dsdb / samdb / ldb_modules / password_hash.c
1 /* 
2    ldb database module
3
4    Copyright (C) Simo Sorce  2004-2006
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Stefan Metzmacher 2007
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /*
24  *  Name: ldb
25  *
26  *  Component: ldb password_hash module
27  *
28  *  Description: correctly update hash values based on changes to userPassword and friends
29  *
30  *  Author: Andrew Bartlett
31  *  Author: Stefan Metzmacher
32  */
33
34 #include "includes.h"
35 #include "libcli/ldap/ldap_ndr.h"
36 #include "ldb/include/ldb_errors.h"
37 #include "ldb/include/ldb.h"
38 #include "ldb/include/ldb_private.h"
39 #include "librpc/gen_ndr/misc.h"
40 #include "librpc/gen_ndr/samr.h"
41 #include "libcli/auth/libcli_auth.h"
42 #include "libcli/security/security.h"
43 #include "system/kerberos.h"
44 #include "auth/kerberos/kerberos.h"
45 #include "system/time.h"
46 #include "dsdb/samdb/samdb.h"
47 #include "dsdb/common/flags.h"
48 #include "dsdb/samdb/ldb_modules/password_modules.h"
49 #include "librpc/ndr/libndr.h"
50 #include "librpc/gen_ndr/ndr_drsblobs.h"
51 #include "lib/crypto/crypto.h"
52 #include "param/param.h"
53
54 /* If we have decided there is reason to work on this request, then
55  * setup all the password hash types correctly.
56  *
57  * If the administrator doesn't want the userPassword stored (set in the
58  * domain and per-account policies) then we must strip that out before
59  * we do the first operation.
60  *
61  * Once this is done (which could update anything at all), we
62  * calculate the password hashes.
63  *
64  * This function must not only update the unicodePwd, dBCSPwd and
65  * supplementalCredentials fields, it must also atomicly increment the
66  * msDS-KeyVersionNumber.  We should be in a transaction, so all this
67  * should be quite safe...
68  *
69  * Finally, if the administrator has requested that a password history
70  * be maintained, then this should also be written out.
71  *
72  */
73
74 struct ph_context {
75
76         enum ph_type {PH_ADD, PH_MOD} type;
77         enum ph_step {PH_ADD_SEARCH_DOM, PH_ADD_DO_ADD, PH_MOD_DO_REQ, PH_MOD_SEARCH_SELF, PH_MOD_SEARCH_DOM, PH_MOD_DO_MOD} step;
78
79         struct ldb_module *module;
80         struct ldb_request *orig_req;
81
82         struct ldb_request *dom_req;
83         struct ldb_reply *dom_res;
84
85         struct ldb_request *down_req;
86
87         struct ldb_request *search_req;
88         struct ldb_reply *search_res;
89
90         struct ldb_request *mod_req;
91
92         struct dom_sid *domain_sid;
93 };
94
95 struct domain_data {
96         bool store_cleartext;
97         uint_t pwdProperties;
98         uint_t pwdHistoryLength;
99         char *netbios_domain;
100         char *dns_domain;
101         char *realm;
102 };
103
104 struct setup_password_fields_io {
105         struct ph_context *ac;
106         struct domain_data *domain;
107         struct smb_krb5_context *smb_krb5_context;
108
109         /* infos about the user account */
110         struct {
111                 uint32_t user_account_control;
112                 const char *sAMAccountName;
113                 const char *user_principal_name;
114                 bool is_computer;
115         } u;
116
117         /* new credentials */
118         struct {
119                 const char *cleartext;
120                 struct samr_Password *nt_hash;
121                 struct samr_Password *lm_hash;
122         } n;
123
124         /* old credentials */
125         struct {
126                 uint32_t nt_history_len;
127                 struct samr_Password *nt_history;
128                 uint32_t lm_history_len;
129                 struct samr_Password *lm_history;
130                 const struct ldb_val *supplemental;
131                 struct supplementalCredentialsBlob scb;
132                 uint32_t kvno;
133         } o;
134
135         /* generated credentials */
136         struct {
137                 struct samr_Password *nt_hash;
138                 struct samr_Password *lm_hash;
139                 uint32_t nt_history_len;
140                 struct samr_Password *nt_history;
141                 uint32_t lm_history_len;
142                 struct samr_Password *lm_history;
143                 const char *salt;
144                 DATA_BLOB aes_256;
145                 DATA_BLOB aes_128;
146                 DATA_BLOB des_md5;
147                 DATA_BLOB des_crc;
148                 struct ldb_val supplemental;
149                 NTTIME last_set;
150                 uint32_t kvno;
151         } g;
152 };
153
154 static int setup_nt_fields(struct setup_password_fields_io *io)
155 {
156         uint32_t i;
157
158         io->g.nt_hash = io->n.nt_hash;
159
160         if (io->domain->pwdHistoryLength == 0) {
161                 return LDB_SUCCESS;
162         }
163
164         /* We might not have an old NT password */
165         io->g.nt_history = talloc_array(io->ac,
166                                         struct samr_Password,
167                                         io->domain->pwdHistoryLength);
168         if (!io->g.nt_history) {
169                 ldb_oom(io->ac->module->ldb);
170                 return LDB_ERR_OPERATIONS_ERROR;
171         }
172
173         for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.nt_history_len); i++) {
174                 io->g.nt_history[i+1] = io->o.nt_history[i];
175         }
176         io->g.nt_history_len = i + 1;
177
178         if (io->g.nt_hash) {
179                 io->g.nt_history[0] = *io->g.nt_hash;
180         } else {
181                 /* 
182                  * TODO: is this correct?
183                  * the simular behavior is correct for the lm history case
184                  */
185                 E_md4hash("", io->g.nt_history[0].hash);
186         }
187
188         return LDB_SUCCESS;
189 }
190
191 static int setup_lm_fields(struct setup_password_fields_io *io)
192 {
193         uint32_t i;
194
195         io->g.lm_hash = io->n.lm_hash;
196
197         if (io->domain->pwdHistoryLength == 0) {
198                 return LDB_SUCCESS;
199         }
200
201         /* We might not have an old NT password */
202         io->g.lm_history = talloc_array(io->ac,
203                                         struct samr_Password,
204                                         io->domain->pwdHistoryLength);
205         if (!io->g.lm_history) {
206                 ldb_oom(io->ac->module->ldb);
207                 return LDB_ERR_OPERATIONS_ERROR;
208         }
209
210         for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.lm_history_len); i++) {
211                 io->g.lm_history[i+1] = io->o.lm_history[i];
212         }
213         io->g.lm_history_len = i + 1;
214
215         if (io->g.lm_hash) {
216                 io->g.lm_history[0] = *io->g.lm_hash;
217         } else {
218                 E_deshash("", io->g.lm_history[0].hash);
219         }
220
221         return LDB_SUCCESS;
222 }
223
224 static int setup_kerberos_keys(struct setup_password_fields_io *io)
225 {
226         krb5_error_code krb5_ret;
227         Principal *salt_principal;
228         krb5_salt salt;
229         krb5_keyblock key;
230
231         /* Many, many thanks to lukeh@padl.com for this
232          * algorithm, described in his Nov 10 2004 mail to
233          * samba-technical@samba.org */
234
235         /*
236          * Determine a salting principal
237          */
238         if (io->u.is_computer) {
239                 char *name;
240                 char *saltbody;
241
242                 name = talloc_strdup(io->ac, io->u.sAMAccountName);
243                 if (!name) {
244                         ldb_oom(io->ac->module->ldb);
245                         return LDB_ERR_OPERATIONS_ERROR;
246                 }
247
248                 if (name[strlen(name)-1] == '$') {
249                         name[strlen(name)-1] = '\0';
250                 }
251
252                 saltbody = talloc_asprintf(io->ac, "%s.%s", name, io->domain->dns_domain);
253                 if (!saltbody) {
254                         ldb_oom(io->ac->module->ldb);
255                         return LDB_ERR_OPERATIONS_ERROR;
256                 }
257                 
258                 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
259                                                &salt_principal,
260                                                io->domain->realm, "host",
261                                                saltbody, NULL);
262         } else if (io->u.user_principal_name) {
263                 char *user_principal_name;
264                 char *p;
265
266                 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
267                 if (!user_principal_name) {
268                         ldb_oom(io->ac->module->ldb);
269                         return LDB_ERR_OPERATIONS_ERROR;
270                 }
271
272                 p = strchr(user_principal_name, '@');
273                 if (p) {
274                         p[0] = '\0';
275                 }
276
277                 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
278                                                &salt_principal,
279                                                io->domain->realm, user_principal_name,
280                                                NULL);
281         } else {
282                 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
283                                                &salt_principal,
284                                                io->domain->realm, io->u.sAMAccountName,
285                                                NULL);
286         }
287         if (krb5_ret) {
288                 ldb_asprintf_errstring(io->ac->module->ldb,
289                                        "setup_kerberos_keys: "
290                                        "generation of a salting principal failed: %s",
291                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
292                 return LDB_ERR_OPERATIONS_ERROR;
293         }
294
295         /*
296          * create salt from salt_principal
297          */
298         krb5_ret = krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
299                                     salt_principal, &salt);
300         krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
301         if (krb5_ret) {
302                 ldb_asprintf_errstring(io->ac->module->ldb,
303                                        "setup_kerberos_keys: "
304                                        "generation of krb5_salt failed: %s",
305                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
306                 return LDB_ERR_OPERATIONS_ERROR;
307         }
308         /* create a talloc copy */
309         io->g.salt = talloc_strndup(io->ac,
310                                     salt.saltvalue.data,
311                                     salt.saltvalue.length);
312         krb5_free_salt(io->smb_krb5_context->krb5_context, salt);
313         if (!io->g.salt) {
314                 ldb_oom(io->ac->module->ldb);
315                 return LDB_ERR_OPERATIONS_ERROR;
316         }
317         salt.saltvalue.data     = discard_const(io->g.salt);
318         salt.saltvalue.length   = strlen(io->g.salt);
319
320         /*
321          * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
322          * the salt and the cleartext password
323          */
324         krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
325                                            ENCTYPE_AES256_CTS_HMAC_SHA1_96,
326                                            io->n.cleartext,
327                                            salt,
328                                            &key);
329         if (krb5_ret) {
330                 ldb_asprintf_errstring(io->ac->module->ldb,
331                                        "setup_kerberos_keys: "
332                                        "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
333                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
334                 return LDB_ERR_OPERATIONS_ERROR;
335         }
336         io->g.aes_256 = data_blob_talloc(io->ac,
337                                          key.keyvalue.data,
338                                          key.keyvalue.length);
339         krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
340         if (!io->g.aes_256.data) {
341                 ldb_oom(io->ac->module->ldb);
342                 return LDB_ERR_OPERATIONS_ERROR;
343         }
344
345         /*
346          * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
347          * the salt and the cleartext password
348          */
349         krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
350                                            ENCTYPE_AES128_CTS_HMAC_SHA1_96,
351                                            io->n.cleartext,
352                                            salt,
353                                            &key);
354         if (krb5_ret) {
355                 ldb_asprintf_errstring(io->ac->module->ldb,
356                                        "setup_kerberos_keys: "
357                                        "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
358                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
359                 return LDB_ERR_OPERATIONS_ERROR;
360         }
361         io->g.aes_128 = data_blob_talloc(io->ac,
362                                          key.keyvalue.data,
363                                          key.keyvalue.length);
364         krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
365         if (!io->g.aes_128.data) {
366                 ldb_oom(io->ac->module->ldb);
367                 return LDB_ERR_OPERATIONS_ERROR;
368         }
369
370         /*
371          * create ENCTYPE_DES_CBC_MD5 key out of
372          * the salt and the cleartext password
373          */
374         krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
375                                            ENCTYPE_DES_CBC_MD5,
376                                            io->n.cleartext,
377                                            salt,
378                                            &key);
379         if (krb5_ret) {
380                 ldb_asprintf_errstring(io->ac->module->ldb,
381                                        "setup_kerberos_keys: "
382                                        "generation of a des-cbc-md5 key failed: %s",
383                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
384                 return LDB_ERR_OPERATIONS_ERROR;
385         }
386         io->g.des_md5 = data_blob_talloc(io->ac,
387                                          key.keyvalue.data,
388                                          key.keyvalue.length);
389         krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
390         if (!io->g.des_md5.data) {
391                 ldb_oom(io->ac->module->ldb);
392                 return LDB_ERR_OPERATIONS_ERROR;
393         }
394
395         /*
396          * create ENCTYPE_DES_CBC_CRC key out of
397          * the salt and the cleartext password
398          */
399         krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
400                                            ENCTYPE_DES_CBC_CRC,
401                                            io->n.cleartext,
402                                            salt,
403                                            &key);
404         if (krb5_ret) {
405                 ldb_asprintf_errstring(io->ac->module->ldb,
406                                        "setup_kerberos_keys: "
407                                        "generation of a des-cbc-crc key failed: %s",
408                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
409                 return LDB_ERR_OPERATIONS_ERROR;
410         }
411         io->g.des_crc = data_blob_talloc(io->ac,
412                                          key.keyvalue.data,
413                                          key.keyvalue.length);
414         krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
415         if (!io->g.des_crc.data) {
416                 ldb_oom(io->ac->module->ldb);
417                 return LDB_ERR_OPERATIONS_ERROR;
418         }
419
420         return LDB_SUCCESS;
421 }
422
423 static int setup_primary_kerberos(struct setup_password_fields_io *io,
424                                   const struct supplementalCredentialsBlob *old_scb,
425                                   struct package_PrimaryKerberosBlob *pkb)
426 {
427         struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
428         struct supplementalCredentialsPackage *old_scp = NULL;
429         struct package_PrimaryKerberosBlob _old_pkb;
430         struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
431         uint32_t i;
432         enum ndr_err_code ndr_err;
433
434         /*
435          * prepare generation of keys
436          *
437          * ENCTYPE_DES_CBC_MD5
438          * ENCTYPE_DES_CBC_CRC
439          */
440         pkb->version            = 3;
441         pkb3->salt.string       = io->g.salt;
442         pkb3->num_keys          = 2;
443         pkb3->keys              = talloc_array(io->ac,
444                                                struct package_PrimaryKerberosKey3,
445                                                pkb3->num_keys);
446         if (!pkb3->keys) {
447                 ldb_oom(io->ac->module->ldb);
448                 return LDB_ERR_OPERATIONS_ERROR;
449         }
450
451         pkb3->keys[0].keytype   = ENCTYPE_DES_CBC_MD5;
452         pkb3->keys[0].value     = &io->g.des_md5;
453         pkb3->keys[1].keytype   = ENCTYPE_DES_CBC_CRC;
454         pkb3->keys[1].value     = &io->g.des_crc;
455
456         /* initialize the old keys to zero */
457         pkb3->num_old_keys      = 0;
458         pkb3->old_keys          = NULL;
459
460         /* if there're no old keys, then we're done */
461         if (!old_scb) {
462                 return LDB_SUCCESS;
463         }
464
465         for (i=0; i < old_scb->sub.num_packages; i++) {
466                 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
467                         continue;
468                 }
469
470                 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
471                         continue;
472                 }
473
474                 old_scp = &old_scb->sub.packages[i];
475                 break;
476         }
477         /* Primary:Kerberos element of supplementalCredentials */
478         if (old_scp) {
479                 DATA_BLOB blob;
480
481                 blob = strhex_to_data_blob(old_scp->data);
482                 if (!blob.data) {
483                         ldb_oom(io->ac->module->ldb);
484                         return LDB_ERR_OPERATIONS_ERROR;
485                 }
486                 talloc_steal(io->ac, blob.data);
487
488                 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
489                 ndr_err = ndr_pull_struct_blob(&blob, io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), &_old_pkb,
490                                                (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
491                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
492                         NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
493                         ldb_asprintf_errstring(io->ac->module->ldb,
494                                                "setup_primary_kerberos: "
495                                                "failed to pull old package_PrimaryKerberosBlob: %s",
496                                                nt_errstr(status));
497                         return LDB_ERR_OPERATIONS_ERROR;
498                 }
499
500                 if (_old_pkb.version != 3) {
501                         ldb_asprintf_errstring(io->ac->module->ldb,
502                                                "setup_primary_kerberos: "
503                                                "package_PrimaryKerberosBlob version[%u] expected[3]",
504                                                _old_pkb.version);
505                         return LDB_ERR_OPERATIONS_ERROR;
506                 }
507
508                 old_pkb3 = &_old_pkb.ctr.ctr3;
509         }
510
511         /* if we didn't found the old keys we're done */
512         if (!old_pkb3) {
513                 return LDB_SUCCESS;
514         }
515
516         /* fill in the old keys */
517         pkb3->num_old_keys      = old_pkb3->num_keys;
518         pkb3->old_keys          = old_pkb3->keys;
519
520         return LDB_SUCCESS;
521 }
522
523 static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
524                                         const struct supplementalCredentialsBlob *old_scb,
525                                         struct package_PrimaryKerberosBlob *pkb)
526 {
527         struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
528         struct supplementalCredentialsPackage *old_scp = NULL;
529         struct package_PrimaryKerberosBlob _old_pkb;
530         struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
531         uint32_t i;
532         enum ndr_err_code ndr_err;
533
534         /*
535          * prepare generation of keys
536          *
537          * ENCTYPE_AES256_CTS_HMAC_SHA1_96
538          * ENCTYPE_AES128_CTS_HMAC_SHA1_96
539          * ENCTYPE_DES_CBC_MD5
540          * ENCTYPE_DES_CBC_CRC
541          */
542         pkb->version                    = 4;
543         pkb4->salt.string               = io->g.salt;
544         pkb4->default_iteration_count   = 4096;
545         pkb4->num_keys                  = 4;
546
547         pkb4->keys = talloc_array(io->ac,
548                                   struct package_PrimaryKerberosKey4,
549                                   pkb4->num_keys);
550         if (!pkb4->keys) {
551                 ldb_oom(io->ac->module->ldb);
552                 return LDB_ERR_OPERATIONS_ERROR;
553         }
554
555         pkb4->keys[0].iteration_count   = 4096;
556         pkb4->keys[0].keytype           = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
557         pkb4->keys[0].value             = &io->g.aes_256;
558         pkb4->keys[1].iteration_count   = 4096;
559         pkb4->keys[1].keytype           = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
560         pkb4->keys[1].value             = &io->g.aes_128;
561         pkb4->keys[2].iteration_count   = 4096;
562         pkb4->keys[2].keytype           = ENCTYPE_DES_CBC_MD5;
563         pkb4->keys[2].value             = &io->g.des_md5;
564         pkb4->keys[3].iteration_count   = 4096;
565         pkb4->keys[3].keytype           = ENCTYPE_DES_CBC_CRC;
566         pkb4->keys[3].value             = &io->g.des_crc;
567
568         /* initialize the old keys to zero */
569         pkb4->num_old_keys      = 0;
570         pkb4->old_keys          = NULL;
571         pkb4->num_older_keys    = 0;
572         pkb4->older_keys        = NULL;
573
574         /* if there're no old keys, then we're done */
575         if (!old_scb) {
576                 return LDB_SUCCESS;
577         }
578
579         for (i=0; i < old_scb->sub.num_packages; i++) {
580                 if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
581                         continue;
582                 }
583
584                 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
585                         continue;
586                 }
587
588                 old_scp = &old_scb->sub.packages[i];
589                 break;
590         }
591         /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
592         if (old_scp) {
593                 DATA_BLOB blob;
594
595                 blob = strhex_to_data_blob(old_scp->data);
596                 if (!blob.data) {
597                         ldb_oom(io->ac->module->ldb);
598                         return LDB_ERR_OPERATIONS_ERROR;
599                 }
600                 talloc_steal(io->ac, blob.data);
601
602                 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
603                 ndr_err = ndr_pull_struct_blob(&blob, io->ac,
604                                                lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
605                                                &_old_pkb,
606                                                (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
607                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
608                         NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
609                         ldb_asprintf_errstring(io->ac->module->ldb,
610                                                "setup_primary_kerberos_newer: "
611                                                "failed to pull old package_PrimaryKerberosBlob: %s",
612                                                nt_errstr(status));
613                         return LDB_ERR_OPERATIONS_ERROR;
614                 }
615
616                 if (_old_pkb.version != 4) {
617                         ldb_asprintf_errstring(io->ac->module->ldb,
618                                                "setup_primary_kerberos_newer: "
619                                                "package_PrimaryKerberosBlob version[%u] expected[4]",
620                                                _old_pkb.version);
621                         return LDB_ERR_OPERATIONS_ERROR;
622                 }
623
624                 old_pkb4 = &_old_pkb.ctr.ctr4;
625         }
626
627         /* if we didn't found the old keys we're done */
628         if (!old_pkb4) {
629                 return LDB_SUCCESS;
630         }
631
632         /* fill in the old keys */
633         pkb4->num_old_keys      = old_pkb4->num_keys;
634         pkb4->old_keys          = old_pkb4->keys;
635         pkb4->num_older_keys    = old_pkb4->num_old_keys;
636         pkb4->older_keys        = old_pkb4->old_keys;
637
638         return LDB_SUCCESS;
639 }
640
641 static int setup_primary_wdigest(struct setup_password_fields_io *io,
642                                  const struct supplementalCredentialsBlob *old_scb,
643                                  struct package_PrimaryWDigestBlob *pdb)
644 {
645         DATA_BLOB sAMAccountName;
646         DATA_BLOB sAMAccountName_l;
647         DATA_BLOB sAMAccountName_u;
648         const char *user_principal_name = io->u.user_principal_name;
649         DATA_BLOB userPrincipalName;
650         DATA_BLOB userPrincipalName_l;
651         DATA_BLOB userPrincipalName_u;
652         DATA_BLOB netbios_domain;
653         DATA_BLOB netbios_domain_l;
654         DATA_BLOB netbios_domain_u;
655         DATA_BLOB dns_domain;
656         DATA_BLOB dns_domain_l;
657         DATA_BLOB dns_domain_u;
658         DATA_BLOB cleartext;
659         DATA_BLOB digest;
660         DATA_BLOB delim;
661         DATA_BLOB backslash;
662         uint8_t i;
663         struct {
664                 DATA_BLOB *user;
665                 DATA_BLOB *realm;
666                 DATA_BLOB *nt4dom;
667         } wdigest[] = {
668         /*
669          * See
670          * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
671          * for what precalculated hashes are supposed to be stored...
672          *
673          * I can't reproduce all values which should contain "Digest" as realm,
674          * am I doing something wrong or is w2k3 just broken...?
675          *
676          * W2K3 fills in following for a user:
677          *
678          * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
679          * sAMAccountName: NewUser2Sam
680          * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
681          *
682          * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
683          * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
684          * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
685          * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
686          * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
687          * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
688          * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
689          * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
690          * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
691          * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
692          * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
693          * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
694          * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
695          * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
696          * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
697          * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
698          * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
699          * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
700          * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
701          * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
702          * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
703          * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
704          * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
705          * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
706          * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
707          * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
708          * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
709          * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
710          * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
711          *
712          * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
713          * sAMAccountName: NewUser2Sam
714          *
715          * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
716          * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
717          * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
718          * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
719          * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
720          * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
721          * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
722          * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
723          * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
724          * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
725          * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
726          * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
727          * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
728          * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
729          * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
730          * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
731          * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
732          * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
733          * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
734          * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
735          * 31dc704d3640335b2123d4ee28aa1f11 => ???M1   changes with NewUser2Sam => NewUser1Sam
736          * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
737          * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
738          * 569b4533f2d9e580211dd040e5e360a8 => ???M2   changes with NewUser2Princ => NewUser1Princ
739          * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
740          * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
741          * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
742          * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
743          * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
744          */
745
746         /*
747          * sAMAccountName, netbios_domain
748          */
749                 {
750                 .user   = &sAMAccountName,
751                 .realm  = &netbios_domain,
752                 },
753                 {
754                 .user   = &sAMAccountName_l,
755                 .realm  = &netbios_domain_l,
756                 },
757                 {
758                 .user   = &sAMAccountName_u,
759                 .realm  = &netbios_domain_u,
760                 },
761                 {
762                 .user   = &sAMAccountName,
763                 .realm  = &netbios_domain_u,
764                 },
765                 {
766                 .user   = &sAMAccountName,
767                 .realm  = &netbios_domain_l,
768                 },
769                 {
770                 .user   = &sAMAccountName_u,
771                 .realm  = &netbios_domain_l,
772                 },
773                 {
774                 .user   = &sAMAccountName_l,
775                 .realm  = &netbios_domain_u,
776                 },
777         /* 
778          * sAMAccountName, dns_domain
779          */
780                 {
781                 .user   = &sAMAccountName,
782                 .realm  = &dns_domain,
783                 },
784                 {
785                 .user   = &sAMAccountName_l,
786                 .realm  = &dns_domain_l,
787                 },
788                 {
789                 .user   = &sAMAccountName_u,
790                 .realm  = &dns_domain_u,
791                 },
792                 {
793                 .user   = &sAMAccountName,
794                 .realm  = &dns_domain_u,
795                 },
796                 {
797                 .user   = &sAMAccountName,
798                 .realm  = &dns_domain_l,
799                 },
800                 {
801                 .user   = &sAMAccountName_u,
802                 .realm  = &dns_domain_l,
803                 },
804                 {
805                 .user   = &sAMAccountName_l,
806                 .realm  = &dns_domain_u,
807                 },
808         /* 
809          * userPrincipalName, no realm
810          */
811                 {
812                 .user   = &userPrincipalName,
813                 },
814                 {
815                 /* 
816                  * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
817                  *       the fallback to the sAMAccountName based userPrincipalName is correct
818                  */
819                 .user   = &userPrincipalName_l,
820                 },
821                 {
822                 .user   = &userPrincipalName_u,
823                 },
824         /* 
825          * nt4dom\sAMAccountName, no realm
826          */
827                 {
828                 .user   = &sAMAccountName,
829                 .nt4dom = &netbios_domain
830                 },
831                 {
832                 .user   = &sAMAccountName_l,
833                 .nt4dom = &netbios_domain_l
834                 },
835                 {
836                 .user   = &sAMAccountName_u,
837                 .nt4dom = &netbios_domain_u
838                 },
839
840         /*
841          * the following ones are guessed depending on the technet2 article
842          * but not reproducable on a w2k3 server
843          */
844         /* sAMAccountName with "Digest" realm */
845                 {
846                 .user   = &sAMAccountName,
847                 .realm  = &digest
848                 },
849                 {
850                 .user   = &sAMAccountName_l,
851                 .realm  = &digest
852                 },
853                 {
854                 .user   = &sAMAccountName_u,
855                 .realm  = &digest
856                 },
857         /* userPrincipalName with "Digest" realm */
858                 {
859                 .user   = &userPrincipalName,
860                 .realm  = &digest
861                 },
862                 {
863                 .user   = &userPrincipalName_l,
864                 .realm  = &digest
865                 },
866                 {
867                 .user   = &userPrincipalName_u,
868                 .realm  = &digest
869                 },
870         /* nt4dom\\sAMAccountName with "Digest" realm */
871                 {
872                 .user   = &sAMAccountName,
873                 .nt4dom = &netbios_domain,
874                 .realm  = &digest
875                 },
876                 {
877                 .user   = &sAMAccountName_l,
878                 .nt4dom = &netbios_domain_l,
879                 .realm  = &digest
880                 },
881                 {
882                 .user   = &sAMAccountName_u,
883                 .nt4dom = &netbios_domain_u,
884                 .realm  = &digest
885                 },
886         };
887
888         /* prepare DATA_BLOB's used in the combinations array */
889         sAMAccountName          = data_blob_string_const(io->u.sAMAccountName);
890         sAMAccountName_l        = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
891         if (!sAMAccountName_l.data) {
892                 ldb_oom(io->ac->module->ldb);
893                 return LDB_ERR_OPERATIONS_ERROR;
894         }
895         sAMAccountName_u        = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
896         if (!sAMAccountName_u.data) {
897                 ldb_oom(io->ac->module->ldb);
898                 return LDB_ERR_OPERATIONS_ERROR;
899         }
900
901         /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
902         if (!user_principal_name) {
903                 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
904                                                       io->u.sAMAccountName,
905                                                       io->domain->dns_domain);
906                 if (!user_principal_name) {
907                         ldb_oom(io->ac->module->ldb);
908                         return LDB_ERR_OPERATIONS_ERROR;
909                 }       
910         }
911         userPrincipalName       = data_blob_string_const(user_principal_name);
912         userPrincipalName_l     = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
913         if (!userPrincipalName_l.data) {
914                 ldb_oom(io->ac->module->ldb);
915                 return LDB_ERR_OPERATIONS_ERROR;
916         }
917         userPrincipalName_u     = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
918         if (!userPrincipalName_u.data) {
919                 ldb_oom(io->ac->module->ldb);
920                 return LDB_ERR_OPERATIONS_ERROR;
921         }
922
923         netbios_domain          = data_blob_string_const(io->domain->netbios_domain);
924         netbios_domain_l        = data_blob_string_const(strlower_talloc(io->ac, io->domain->netbios_domain));
925         if (!netbios_domain_l.data) {
926                 ldb_oom(io->ac->module->ldb);
927                 return LDB_ERR_OPERATIONS_ERROR;
928         }
929         netbios_domain_u        = data_blob_string_const(strupper_talloc(io->ac, io->domain->netbios_domain));
930         if (!netbios_domain_u.data) {
931                 ldb_oom(io->ac->module->ldb);
932                 return LDB_ERR_OPERATIONS_ERROR;
933         }
934
935         dns_domain              = data_blob_string_const(io->domain->dns_domain);
936         dns_domain_l            = data_blob_string_const(io->domain->dns_domain);
937         dns_domain_u            = data_blob_string_const(io->domain->realm);
938
939         cleartext               = data_blob_string_const(io->n.cleartext);
940
941         digest                  = data_blob_string_const("Digest");
942
943         delim                   = data_blob_string_const(":");
944         backslash               = data_blob_string_const("\\");
945
946         pdb->num_hashes = ARRAY_SIZE(wdigest);
947         pdb->hashes     = talloc_array(io->ac, struct package_PrimaryWDigestHash, pdb->num_hashes);
948         if (!pdb->hashes) {
949                 ldb_oom(io->ac->module->ldb);
950                 return LDB_ERR_OPERATIONS_ERROR;
951         }
952
953         for (i=0; i < ARRAY_SIZE(wdigest); i++) {
954                 struct MD5Context md5;
955                 MD5Init(&md5);
956                 if (wdigest[i].nt4dom) {
957                         MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
958                         MD5Update(&md5, backslash.data, backslash.length);
959                 }
960                 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
961                 MD5Update(&md5, delim.data, delim.length);
962                 if (wdigest[i].realm) {
963                         MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
964                 }
965                 MD5Update(&md5, delim.data, delim.length);
966                 MD5Update(&md5, cleartext.data, cleartext.length);
967                 MD5Final(pdb->hashes[i].hash, &md5);
968         }
969
970         return LDB_SUCCESS;
971 }
972
973 static int setup_supplemental_field(struct setup_password_fields_io *io)
974 {
975         struct supplementalCredentialsBlob scb;
976         struct supplementalCredentialsBlob _old_scb;
977         struct supplementalCredentialsBlob *old_scb = NULL;
978         /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */
979         uint32_t num_names = 0;
980         const char *names[1+4];
981         uint32_t num_packages = 0;
982         struct supplementalCredentialsPackage packages[1+4];
983         /* Packages */
984         struct supplementalCredentialsPackage *pp = NULL;
985         struct package_PackagesBlob pb;
986         DATA_BLOB pb_blob;
987         char *pb_hexstr;
988         /* Primary:Kerberos-Newer-Keys */
989         const char **nkn = NULL;
990         struct supplementalCredentialsPackage *pkn = NULL;
991         struct package_PrimaryKerberosBlob pknb;
992         DATA_BLOB pknb_blob;
993         char *pknb_hexstr;
994         /* Primary:Kerberos */
995         const char **nk = NULL;
996         struct supplementalCredentialsPackage *pk = NULL;
997         struct package_PrimaryKerberosBlob pkb;
998         DATA_BLOB pkb_blob;
999         char *pkb_hexstr;
1000         /* Primary:WDigest */
1001         const char **nd = NULL;
1002         struct supplementalCredentialsPackage *pd = NULL;
1003         struct package_PrimaryWDigestBlob pdb;
1004         DATA_BLOB pdb_blob;
1005         char *pdb_hexstr;
1006         /* Primary:CLEARTEXT */
1007         const char **nc = NULL;
1008         struct supplementalCredentialsPackage *pc = NULL;
1009         struct package_PrimaryCLEARTEXTBlob pcb;
1010         DATA_BLOB pcb_blob;
1011         char *pcb_hexstr;
1012         int ret;
1013         enum ndr_err_code ndr_err;
1014         uint8_t zero16[16];
1015         bool do_newer_keys = false;
1016         bool do_cleartext = false;
1017
1018         ZERO_STRUCT(zero16);
1019         ZERO_STRUCT(names);
1020
1021         if (!io->n.cleartext) {
1022                 /* 
1023                  * when we don't have a cleartext password
1024                  * we can't setup a supplementalCredential value
1025                  */
1026                 return LDB_SUCCESS;
1027         }
1028
1029         /* if there's an old supplementaCredentials blob then parse it */
1030         if (io->o.supplemental) {
1031                 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
1032                                                    lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1033                                                    &_old_scb,
1034                                                    (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
1035                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1036                         NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1037                         ldb_asprintf_errstring(io->ac->module->ldb,
1038                                                "setup_supplemental_field: "
1039                                                "failed to pull old supplementalCredentialsBlob: %s",
1040                                                nt_errstr(status));
1041                         return LDB_ERR_OPERATIONS_ERROR;
1042                 }
1043
1044                 if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1045                         old_scb = &_old_scb;
1046                 } else {
1047                         ldb_debug(io->ac->module->ldb, LDB_DEBUG_ERROR,
1048                                                "setup_supplemental_field: "
1049                                                "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
1050                                                _old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
1051                 }
1052         }
1053
1054         /* TODO: do the correct check for this, it maybe depends on the functional level? */
1055         do_newer_keys = lp_parm_bool(ldb_get_opaque(io->ac->module->ldb, "loadparm"),
1056                                      NULL, "password_hash", "create_aes_key", false);
1057
1058         if (io->domain->store_cleartext &&
1059             (io->u.user_account_control & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
1060                 do_cleartext = true;
1061         }
1062
1063         /*
1064          * The ordering is this
1065          *
1066          * Primary:Kerberos-Newer-Keys (optional)
1067          * Primary:Kerberos
1068          * Primary:WDigest
1069          * Primary:CLEARTEXT (optional)
1070          *
1071          * And the 'Packages' package is insert before the last
1072          * other package.
1073          */
1074         if (do_newer_keys) {
1075                 /* Primary:Kerberos-Newer-Keys */
1076                 nkn = &names[num_names++];
1077                 pkn = &packages[num_packages++];
1078         }
1079
1080         /* Primary:Kerberos */
1081         nk = &names[num_names++];
1082         pk = &packages[num_packages++];
1083
1084         if (!do_cleartext) {
1085                 /* Packages */
1086                 pp = &packages[num_packages++];
1087         }
1088
1089         /* Primary:WDigest */
1090         nd = &names[num_names++];
1091         pd = &packages[num_packages++];
1092
1093         if (do_cleartext) {
1094                 /* Packages */
1095                 pp = &packages[num_packages++];
1096
1097                 /* Primary:CLEARTEXT */
1098                 nc = &names[num_names++];
1099                 pc = &packages[num_packages++];
1100         }
1101
1102         if (pkn) {
1103                 /*
1104                  * setup 'Primary:Kerberos-Newer-Keys' element
1105                  */
1106                 *nkn = "Kerberos-Newer-Keys";
1107
1108                 ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
1109                 if (ret != LDB_SUCCESS) {
1110                         return ret;
1111                 }
1112
1113                 ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac,
1114                                                lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1115                                                &pknb,
1116                                                (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1117                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1118                         NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1119                         ldb_asprintf_errstring(io->ac->module->ldb,
1120                                                "setup_supplemental_field: "
1121                                                "failed to push package_PrimaryKerberosNeverBlob: %s",
1122                                                nt_errstr(status));
1123                         return LDB_ERR_OPERATIONS_ERROR;
1124                 }
1125                 pknb_hexstr = data_blob_hex_string(io->ac, &pknb_blob);
1126                 if (!pknb_hexstr) {
1127                         ldb_oom(io->ac->module->ldb);
1128                         return LDB_ERR_OPERATIONS_ERROR;
1129                 }
1130                 pkn->name       = "Primary:Kerberos-Newer-Keys";
1131                 pkn->reserved   = 1;
1132                 pkn->data       = pknb_hexstr;
1133         }
1134
1135         /*
1136          * setup 'Primary:Kerberos' element
1137          */
1138         *nk = "Kerberos";
1139
1140         ret = setup_primary_kerberos(io, old_scb, &pkb);
1141         if (ret != LDB_SUCCESS) {
1142                 return ret;
1143         }
1144
1145         ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac, 
1146                                        lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1147                                        &pkb,
1148                                        (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
1149         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1150                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1151                 ldb_asprintf_errstring(io->ac->module->ldb,
1152                                        "setup_supplemental_field: "
1153                                        "failed to push package_PrimaryKerberosBlob: %s",
1154                                        nt_errstr(status));
1155                 return LDB_ERR_OPERATIONS_ERROR;
1156         }
1157         pkb_hexstr = data_blob_hex_string(io->ac, &pkb_blob);
1158         if (!pkb_hexstr) {
1159                 ldb_oom(io->ac->module->ldb);
1160                 return LDB_ERR_OPERATIONS_ERROR;
1161         }
1162         pk->name        = "Primary:Kerberos";
1163         pk->reserved    = 1;
1164         pk->data        = pkb_hexstr;
1165
1166         /*
1167          * setup 'Primary:WDigest' element
1168          */
1169         *nd = "WDigest";
1170
1171         ret = setup_primary_wdigest(io, old_scb, &pdb);
1172         if (ret != LDB_SUCCESS) {
1173                 return ret;
1174         }
1175
1176         ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac, 
1177                                        lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1178                                        &pdb,
1179                                        (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
1180         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1181                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1182                 ldb_asprintf_errstring(io->ac->module->ldb,
1183                                        "setup_supplemental_field: "
1184                                        "failed to push package_PrimaryWDigestBlob: %s",
1185                                        nt_errstr(status));
1186                 return LDB_ERR_OPERATIONS_ERROR;
1187         }
1188         pdb_hexstr = data_blob_hex_string(io->ac, &pdb_blob);
1189         if (!pdb_hexstr) {
1190                 ldb_oom(io->ac->module->ldb);
1191                 return LDB_ERR_OPERATIONS_ERROR;
1192         }
1193         pd->name        = "Primary:WDigest";
1194         pd->reserved    = 1;
1195         pd->data        = pdb_hexstr;
1196
1197         /*
1198          * setup 'Primary:CLEARTEXT' element
1199          */
1200         if (pc) {
1201                 *nc             = "CLEARTEXT";
1202
1203                 pcb.cleartext   = io->n.cleartext;
1204
1205                 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac, 
1206                                                lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1207                                                &pcb,
1208                                                (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
1209                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1210                         NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1211                         ldb_asprintf_errstring(io->ac->module->ldb,
1212                                                "setup_supplemental_field: "
1213                                                "failed to push package_PrimaryCLEARTEXTBlob: %s",
1214                                                nt_errstr(status));
1215                         return LDB_ERR_OPERATIONS_ERROR;
1216                 }
1217                 pcb_hexstr = data_blob_hex_string(io->ac, &pcb_blob);
1218                 if (!pcb_hexstr) {
1219                         ldb_oom(io->ac->module->ldb);
1220                         return LDB_ERR_OPERATIONS_ERROR;
1221                 }
1222                 pc->name        = "Primary:CLEARTEXT";
1223                 pc->reserved    = 1;
1224                 pc->data        = pcb_hexstr;
1225         }
1226
1227         /*
1228          * setup 'Packages' element
1229          */
1230         pb.names = names;
1231         ndr_err = ndr_push_struct_blob(&pb_blob, io->ac, 
1232                                        lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), 
1233                                        &pb,
1234                                        (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1235         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1236                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1237                 ldb_asprintf_errstring(io->ac->module->ldb,
1238                                        "setup_supplemental_field: "
1239                                        "failed to push package_PackagesBlob: %s",
1240                                        nt_errstr(status));
1241                 return LDB_ERR_OPERATIONS_ERROR;
1242         }
1243         pb_hexstr = data_blob_hex_string(io->ac, &pb_blob);
1244         if (!pb_hexstr) {
1245                 ldb_oom(io->ac->module->ldb);
1246                 return LDB_ERR_OPERATIONS_ERROR;
1247         }
1248         pp->name        = "Packages";
1249         pp->reserved    = 2;
1250         pp->data        = pb_hexstr;
1251
1252         /*
1253          * setup 'supplementalCredentials' value
1254          */
1255         ZERO_STRUCT(scb);
1256         scb.sub.num_packages    = num_packages;
1257         scb.sub.packages        = packages;
1258
1259         ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac, 
1260                                        lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1261                                        &scb,
1262                                        (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1263         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1264                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1265                 ldb_asprintf_errstring(io->ac->module->ldb,
1266                                        "setup_supplemental_field: "
1267                                        "failed to push supplementalCredentialsBlob: %s",
1268                                        nt_errstr(status));
1269                 return LDB_ERR_OPERATIONS_ERROR;
1270         }
1271
1272         return LDB_SUCCESS;
1273 }
1274
1275 static int setup_last_set_field(struct setup_password_fields_io *io)
1276 {
1277         /* set it as now */
1278         unix_to_nt_time(&io->g.last_set, time(NULL));
1279
1280         return LDB_SUCCESS;
1281 }
1282
1283 static int setup_kvno_field(struct setup_password_fields_io *io)
1284 {
1285         /* increment by one */
1286         io->g.kvno = io->o.kvno + 1;
1287
1288         return LDB_SUCCESS;
1289 }
1290
1291 static int setup_password_fields(struct setup_password_fields_io *io)
1292 {
1293         bool ok;
1294         int ret;
1295
1296         /*
1297          * refuse the change if someone want to change the cleartext
1298          * and supply his own hashes at the same time...
1299          */
1300         if (io->n.cleartext && (io->n.nt_hash || io->n.lm_hash)) {
1301                 ldb_asprintf_errstring(io->ac->module->ldb,
1302                                        "setup_password_fields: "
1303                                        "it's only allowed to set the cleartext password or the password hashes");
1304                 return LDB_ERR_UNWILLING_TO_PERFORM;
1305         }
1306
1307         if (io->n.cleartext) {
1308                 struct samr_Password *hash;
1309
1310                 hash = talloc(io->ac, struct samr_Password);
1311                 if (!hash) {
1312                         ldb_oom(io->ac->module->ldb);
1313                         return LDB_ERR_OPERATIONS_ERROR;
1314                 }
1315
1316                 /* compute the new nt hash */
1317                 ok = E_md4hash(io->n.cleartext, hash->hash);
1318                 if (ok) {
1319                         io->n.nt_hash = hash;
1320                 } else {
1321                         ldb_asprintf_errstring(io->ac->module->ldb,
1322                                                "setup_password_fields: "
1323                                                "failed to generate nthash from cleartext password");
1324                         return LDB_ERR_OPERATIONS_ERROR;
1325                 }
1326         }
1327
1328         if (io->n.cleartext) {
1329                 struct samr_Password *hash;
1330
1331                 hash = talloc(io->ac, struct samr_Password);
1332                 if (!hash) {
1333                         ldb_oom(io->ac->module->ldb);
1334                         return LDB_ERR_OPERATIONS_ERROR;
1335                 }
1336
1337                 /* compute the new lm hash */
1338                 ok = E_deshash(io->n.cleartext, hash->hash);
1339                 if (ok) {
1340                         io->n.lm_hash = hash;
1341                 } else {
1342                         talloc_free(hash->hash);
1343                 }
1344         }
1345
1346         if (io->n.cleartext) {
1347                 ret = setup_kerberos_keys(io);
1348                 if (ret != 0) {
1349                         return ret;
1350                 }
1351         }
1352
1353         ret = setup_nt_fields(io);
1354         if (ret != 0) {
1355                 return ret;
1356         }
1357
1358         ret = setup_lm_fields(io);
1359         if (ret != 0) {
1360                 return ret;
1361         }
1362
1363         ret = setup_supplemental_field(io);
1364         if (ret != 0) {
1365                 return ret;
1366         }
1367
1368         ret = setup_last_set_field(io);
1369         if (ret != 0) {
1370                 return ret;
1371         }
1372
1373         ret = setup_kvno_field(io);
1374         if (ret != 0) {
1375                 return ret;
1376         }
1377
1378         return LDB_SUCCESS;
1379 }
1380
1381 static struct ldb_handle *ph_init_handle(struct ldb_request *req, struct ldb_module *module, enum ph_type type)
1382 {
1383         struct ph_context *ac;
1384         struct ldb_handle *h;
1385
1386         h = talloc_zero(req, struct ldb_handle);
1387         if (h == NULL) {
1388                 ldb_set_errstring(module->ldb, "Out of Memory");
1389                 return NULL;
1390         }
1391
1392         h->module = module;
1393
1394         ac = talloc_zero(h, struct ph_context);
1395         if (ac == NULL) {
1396                 ldb_set_errstring(module->ldb, "Out of Memory");
1397                 talloc_free(h);
1398                 return NULL;
1399         }
1400
1401         h->private_data = (void *)ac;
1402
1403         h->state = LDB_ASYNC_INIT;
1404         h->status = LDB_SUCCESS;
1405
1406         ac->type = type;
1407         ac->module = module;
1408         ac->orig_req = req;
1409
1410         return h;
1411 }
1412
1413 static int get_domain_data_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
1414 {
1415         struct ph_context *ac;
1416
1417         ac = talloc_get_type(context, struct ph_context);
1418
1419         /* we are interested only in the single reply (base search) we receive here */
1420         if (ares->type == LDB_REPLY_ENTRY) {
1421                 if (ac->dom_res != NULL) {
1422                         ldb_set_errstring(ldb, "Too many results");
1423                         talloc_free(ares);
1424                         return LDB_ERR_OPERATIONS_ERROR;
1425                 }
1426                 ac->dom_res = talloc_steal(ac, ares);
1427         } else {
1428                 talloc_free(ares);
1429         }
1430
1431         return LDB_SUCCESS;
1432 }
1433
1434 static int build_domain_data_request(struct ph_context *ac)
1435 {
1436         /* attrs[] is returned from this function in
1437            ac->dom_req->op.search.attrs, so it must be static, as
1438            otherwise the compiler can put it on the stack */
1439         static const char * const attrs[] = { "pwdProperties", "pwdHistoryLength", NULL };
1440         char *filter;
1441
1442         ac->dom_req = talloc_zero(ac, struct ldb_request);
1443         if (ac->dom_req == NULL) {
1444                 ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
1445                 return LDB_ERR_OPERATIONS_ERROR;
1446         }
1447         ac->dom_req->operation = LDB_SEARCH;
1448         ac->dom_req->op.search.base = ldb_get_default_basedn(ac->module->ldb);
1449         ac->dom_req->op.search.scope = LDB_SCOPE_SUBTREE;
1450
1451         filter = talloc_asprintf(ac->dom_req,
1452                                  "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))", 
1453                                  ldap_encode_ndr_dom_sid(ac->dom_req, ac->domain_sid));
1454         if (filter == NULL) {
1455                 ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
1456                 talloc_free(ac->dom_req);
1457                 return LDB_ERR_OPERATIONS_ERROR;
1458         }
1459
1460         ac->dom_req->op.search.tree = ldb_parse_tree(ac->dom_req, filter);
1461         if (ac->dom_req->op.search.tree == NULL) {
1462                 ldb_set_errstring(ac->module->ldb, "Invalid search filter");
1463                 talloc_free(ac->dom_req);
1464                 return LDB_ERR_OPERATIONS_ERROR;
1465         }
1466         ac->dom_req->op.search.attrs = attrs;
1467         ac->dom_req->controls = NULL;
1468         ac->dom_req->context = ac;
1469         ac->dom_req->callback = get_domain_data_callback;
1470         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->dom_req);
1471
1472         return LDB_SUCCESS;
1473 }
1474
1475 static struct domain_data *get_domain_data(struct ldb_module *module, void *ctx, struct ldb_reply *res)
1476 {
1477         struct domain_data *data;
1478         const char *tmp;
1479         struct ph_context *ac;
1480         char *p;
1481
1482         ac = talloc_get_type(ctx, struct ph_context);
1483
1484         data = talloc_zero(ac, struct domain_data);
1485         if (data == NULL) {
1486                 return NULL;
1487         }
1488
1489         if (res == NULL) {
1490                 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Could not find this user's domain: %s!\n", dom_sid_string(data, ac->domain_sid));
1491                 talloc_free(data);
1492                 return NULL;
1493         }
1494
1495         data->pwdProperties= samdb_result_uint(res->message, "pwdProperties", 0);
1496         data->store_cleartext = data->pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
1497         data->pwdHistoryLength = samdb_result_uint(res->message, "pwdHistoryLength", 0);
1498
1499         /* For a domain DN, this puts things in dotted notation */
1500         /* For builtin domains, this will give details for the host,
1501          * but that doesn't really matter, as it's just used for salt
1502          * and kerberos principals, which don't exist here */
1503
1504         tmp = ldb_dn_canonical_string(ctx, res->message->dn);
1505         if (!tmp) {
1506                 return NULL;
1507         }
1508         
1509         /* But it puts a trailing (or just before 'builtin') / on things, so kill that */
1510         p = strchr(tmp, '/');
1511         if (p) {
1512                 p[0] = '\0';
1513         }
1514
1515         if (tmp != NULL) {
1516                 data->dns_domain = strlower_talloc(data, tmp);
1517                 if (data->dns_domain == NULL) {
1518                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of memory!\n");
1519                         return NULL;
1520                 }
1521                 data->realm = strupper_talloc(data, tmp);
1522                 if (data->realm == NULL) {
1523                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of memory!\n");
1524                         return NULL;
1525                 }
1526                 p = strchr(tmp, '.');
1527                 if (p) {
1528                         p[0] = '\0';
1529                 }
1530                 data->netbios_domain = strupper_talloc(data, tmp);
1531                 if (data->netbios_domain == NULL) {
1532                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of memory!\n");
1533                         return NULL;
1534                 }
1535         }
1536
1537         return data;
1538 }
1539
1540 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
1541 {
1542         struct ldb_handle *h;
1543         struct ph_context *ac;
1544         struct ldb_message_element *sambaAttr;
1545         struct ldb_message_element *ntAttr;
1546         struct ldb_message_element *lmAttr;
1547         int ret;
1548
1549         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
1550
1551         if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
1552                 return ldb_next_request(module, req);
1553         }
1554
1555         /* If the caller is manipulating the local passwords directly, let them pass */
1556         if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
1557                                 req->op.add.message->dn) == 0) {
1558                 return ldb_next_request(module, req);
1559         }
1560
1561         /* nobody must touch this fields */
1562         if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1563                 return LDB_ERR_UNWILLING_TO_PERFORM;
1564         }
1565         if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1566                 return LDB_ERR_UNWILLING_TO_PERFORM;
1567         }
1568         if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1569                 return LDB_ERR_UNWILLING_TO_PERFORM;
1570         }
1571
1572         /* If no part of this ADD touches the userPassword, or the NT
1573          * or LM hashes, then we don't need to make any changes.  */
1574
1575         sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1576         ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1577         lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1578
1579         if ((!sambaAttr) && (!ntAttr) && (!lmAttr)) {
1580                 return ldb_next_request(module, req);
1581         }
1582
1583         /* if it is not an entry of type person its an error */
1584         /* TODO: remove this when userPassword will be in schema */
1585         if (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "person")) {
1586                 ldb_set_errstring(module->ldb, "Cannot set a password on entry that does not have objectClass 'person'");
1587                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1588         }
1589
1590         /* check userPassword is single valued here */
1591         /* TODO: remove this when userPassword will be single valued in schema */
1592         if (sambaAttr && sambaAttr->num_values > 1) {
1593                 ldb_set_errstring(module->ldb, "mupltiple values for userPassword not allowed!\n");
1594                 return LDB_ERR_CONSTRAINT_VIOLATION;
1595         }
1596
1597         if (ntAttr && (ntAttr->num_values > 1)) {
1598                 ldb_set_errstring(module->ldb, "mupltiple values for unicodePwd not allowed!\n");
1599                 return LDB_ERR_CONSTRAINT_VIOLATION;
1600         }
1601         if (lmAttr && (lmAttr->num_values > 1)) {
1602                 ldb_set_errstring(module->ldb, "mupltiple values for dBCSPwd not allowed!\n");
1603                 return LDB_ERR_CONSTRAINT_VIOLATION;
1604         }
1605
1606         if (sambaAttr && sambaAttr->num_values == 0) {
1607                 ldb_set_errstring(module->ldb, "userPassword must have a value!\n");
1608                 return LDB_ERR_CONSTRAINT_VIOLATION;
1609         }
1610
1611         if (ntAttr && (ntAttr->num_values == 0)) {
1612                 ldb_set_errstring(module->ldb, "unicodePwd must have a value!\n");
1613                 return LDB_ERR_CONSTRAINT_VIOLATION;
1614         }
1615         if (lmAttr && (lmAttr->num_values == 0)) {
1616                 ldb_set_errstring(module->ldb, "dBCSPwd must have a value!\n");
1617                 return LDB_ERR_CONSTRAINT_VIOLATION;
1618         }
1619
1620         h = ph_init_handle(req, module, PH_ADD);
1621         if (!h) {
1622                 return LDB_ERR_OPERATIONS_ERROR;
1623         }
1624         ac = talloc_get_type(h->private_data, struct ph_context);
1625
1626         /* get user domain data */
1627         ac->domain_sid = samdb_result_sid_prefix(ac, req->op.add.message, "objectSid");
1628         if (ac->domain_sid == NULL) {
1629                 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "can't handle entry with missing objectSid!\n");
1630                 return LDB_ERR_OPERATIONS_ERROR;
1631         }
1632
1633         ret = build_domain_data_request(ac);
1634         if (ret != LDB_SUCCESS) {
1635                 return ret;
1636         }
1637
1638         ac->step = PH_ADD_SEARCH_DOM;
1639
1640         req->handle = h;
1641
1642         return ldb_next_request(module, ac->dom_req);
1643 }
1644
1645 static int password_hash_add_do_add(struct ldb_handle *h) {
1646
1647         struct ph_context *ac;
1648         struct domain_data *domain;
1649         struct smb_krb5_context *smb_krb5_context;
1650         struct ldb_message *msg;
1651         struct setup_password_fields_io io;
1652         int ret;
1653
1654         ac = talloc_get_type(h->private_data, struct ph_context);
1655
1656         domain = get_domain_data(ac->module, ac, ac->dom_res);
1657         if (domain == NULL) {
1658                 return LDB_ERR_OPERATIONS_ERROR;
1659         }
1660
1661         ac->down_req = talloc(ac, struct ldb_request);
1662         if (ac->down_req == NULL) {
1663                 return LDB_ERR_OPERATIONS_ERROR;
1664         }
1665
1666         *(ac->down_req) = *(ac->orig_req);
1667         ac->down_req->op.add.message = msg = ldb_msg_copy_shallow(ac->down_req, ac->orig_req->op.add.message);
1668         if (ac->down_req->op.add.message == NULL) {
1669                 return LDB_ERR_OPERATIONS_ERROR;
1670         }
1671
1672         /* Some operations below require kerberos contexts */
1673         if (smb_krb5_init_context(ac->down_req, 
1674                                   ldb_get_opaque(h->module->ldb, "EventContext"), 
1675                                   (struct loadparm_context *)ldb_get_opaque(h->module->ldb, "loadparm"), 
1676                                   &smb_krb5_context) != 0) {
1677                 return LDB_ERR_OPERATIONS_ERROR;
1678         }
1679
1680         ZERO_STRUCT(io);
1681         io.ac                           = ac;
1682         io.domain                       = domain;
1683         io.smb_krb5_context             = smb_krb5_context;
1684
1685         io.u.user_account_control       = samdb_result_uint(msg, "userAccountControl", 0);
1686         io.u.sAMAccountName             = samdb_result_string(msg, "samAccountName", NULL);
1687         io.u.user_principal_name        = samdb_result_string(msg, "userPrincipalName", NULL);
1688         io.u.is_computer                = ldb_msg_check_string_attribute(msg, "objectClass", "computer");
1689
1690         io.n.cleartext                  = samdb_result_string(msg, "userPassword", NULL);
1691         io.n.nt_hash                    = samdb_result_hash(io.ac, msg, "unicodePwd");
1692         io.n.lm_hash                    = samdb_result_hash(io.ac, msg, "dBCSPwd");
1693
1694         /* remove attributes */
1695         if (io.n.cleartext) ldb_msg_remove_attr(msg, "userPassword");
1696         if (io.n.nt_hash) ldb_msg_remove_attr(msg, "unicodePwd");
1697         if (io.n.lm_hash) ldb_msg_remove_attr(msg, "dBCSPwd");
1698         ldb_msg_remove_attr(msg, "pwdLastSet");
1699         io.o.kvno = samdb_result_uint(msg, "msDs-KeyVersionNumber", 1) - 1;
1700         ldb_msg_remove_attr(msg, "msDs-KeyVersionNumber");
1701
1702         ret = setup_password_fields(&io);
1703         if (ret != LDB_SUCCESS) {
1704                 return ret;
1705         }
1706
1707         if (io.g.nt_hash) {
1708                 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
1709                                          "unicodePwd", io.g.nt_hash);
1710                 if (ret != LDB_SUCCESS) {
1711                         return ret;
1712                 }
1713         }
1714         if (io.g.lm_hash) {
1715                 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
1716                                          "dBCSPwd", io.g.lm_hash);
1717                 if (ret != LDB_SUCCESS) {
1718                         return ret;
1719                 }
1720         }
1721         if (io.g.nt_history_len > 0) {
1722                 ret = samdb_msg_add_hashes(ac, msg,
1723                                            "ntPwdHistory",
1724                                            io.g.nt_history,
1725                                            io.g.nt_history_len);
1726                 if (ret != LDB_SUCCESS) {
1727                         return ret;
1728                 }
1729         }
1730         if (io.g.lm_history_len > 0) {
1731                 ret = samdb_msg_add_hashes(ac, msg,
1732                                            "lmPwdHistory",
1733                                            io.g.lm_history,
1734                                            io.g.lm_history_len);
1735                 if (ret != LDB_SUCCESS) {
1736                         return ret;
1737                 }
1738         }
1739         if (io.g.supplemental.length > 0) {
1740                 ret = ldb_msg_add_value(msg, "supplementalCredentials",
1741                                         &io.g.supplemental, NULL);
1742                 if (ret != LDB_SUCCESS) {
1743                         return ret;
1744                 }
1745         }
1746         ret = samdb_msg_add_uint64(ac->module->ldb, ac, msg,
1747                                    "pwdLastSet",
1748                                    io.g.last_set);
1749         if (ret != LDB_SUCCESS) {
1750                 return ret;
1751         }
1752         ret = samdb_msg_add_uint(ac->module->ldb, ac, msg,
1753                                  "msDs-KeyVersionNumber",
1754                                  io.g.kvno);
1755         if (ret != LDB_SUCCESS) {
1756                 return ret;
1757         }
1758
1759         h->state = LDB_ASYNC_INIT;
1760         h->status = LDB_SUCCESS;
1761
1762         ac->step = PH_ADD_DO_ADD;
1763
1764         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->down_req);
1765
1766         /* perform the operation */
1767         return ldb_next_request(ac->module, ac->down_req);
1768 }
1769
1770 static int password_hash_mod_search_self(struct ldb_handle *h);
1771
1772 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
1773 {
1774         struct ldb_handle *h;
1775         struct ph_context *ac;
1776         struct ldb_message_element *sambaAttr;
1777         struct ldb_message_element *ntAttr;
1778         struct ldb_message_element *lmAttr;
1779         struct ldb_message *msg;
1780
1781         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
1782
1783         if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1784                 return ldb_next_request(module, req);
1785         }
1786         
1787         /* If the caller is manipulating the local passwords directly, let them pass */
1788         if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
1789                                 req->op.mod.message->dn) == 0) {
1790                 return ldb_next_request(module, req);
1791         }
1792
1793         /* nobody must touch password Histories */
1794         if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1795                 return LDB_ERR_UNWILLING_TO_PERFORM;
1796         }
1797         if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1798                 return LDB_ERR_UNWILLING_TO_PERFORM;
1799         }
1800         if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1801                 return LDB_ERR_UNWILLING_TO_PERFORM;
1802         }
1803
1804         sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1805         ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1806         lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1807
1808         /* If no part of this touches the userPassword OR unicodePwd and/or dBCSPwd, then we don't
1809          * need to make any changes.  For password changes/set there should
1810          * be a 'delete' or a 'modify' on this attribute. */
1811         if ((!sambaAttr) && (!ntAttr) && (!lmAttr)) {
1812                 return ldb_next_request(module, req);
1813         }
1814
1815         /* check passwords are single valued here */
1816         /* TODO: remove this when passwords will be single valued in schema */
1817         if (sambaAttr && (sambaAttr->num_values > 1)) {
1818                 return LDB_ERR_CONSTRAINT_VIOLATION;
1819         }
1820         if (ntAttr && (ntAttr->num_values > 1)) {
1821                 return LDB_ERR_CONSTRAINT_VIOLATION;
1822         }
1823         if (lmAttr && (lmAttr->num_values > 1)) {
1824                 return LDB_ERR_CONSTRAINT_VIOLATION;
1825         }
1826
1827         h = ph_init_handle(req, module, PH_MOD);
1828         if (!h) {
1829                 return LDB_ERR_OPERATIONS_ERROR;
1830         }
1831         ac = talloc_get_type(h->private_data, struct ph_context);
1832
1833         /* return or own handle to deal with this call */
1834         req->handle = h;
1835
1836         /* prepare the first operation */
1837         ac->down_req = talloc_zero(ac, struct ldb_request);
1838         if (ac->down_req == NULL) {
1839                 ldb_set_errstring(module->ldb, "Out of memory!");
1840                 return LDB_ERR_OPERATIONS_ERROR;
1841         }
1842
1843         *(ac->down_req) = *req; /* copy the request */
1844
1845         /* use a new message structure so that we can modify it */
1846         ac->down_req->op.mod.message = msg = ldb_msg_copy_shallow(ac->down_req, req->op.mod.message);
1847
1848         /* - remove any imodification to the password from the first commit
1849          *   we will make the real modification later */
1850         if (sambaAttr) ldb_msg_remove_attr(msg, "userPassword");
1851         if (ntAttr) ldb_msg_remove_attr(msg, "unicodePwd");
1852         if (lmAttr) ldb_msg_remove_attr(msg, "dBCSPwd");
1853
1854         /* if there was nothing else to be modify skip to next step */
1855         if (msg->num_elements == 0) {
1856                 talloc_free(ac->down_req);
1857                 ac->down_req = NULL;
1858                 return password_hash_mod_search_self(h);
1859         }
1860         
1861         ac->down_req->context = NULL;
1862         ac->down_req->callback = NULL;
1863
1864         ac->step = PH_MOD_DO_REQ;
1865
1866         ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
1867
1868         return ldb_next_request(module, ac->down_req);
1869 }
1870
1871 static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
1872 {
1873         struct ph_context *ac;
1874
1875         ac = talloc_get_type(context, struct ph_context);
1876
1877         /* we are interested only in the single reply (base search) we receive here */
1878         if (ares->type == LDB_REPLY_ENTRY) {
1879                 if (ac->search_res != NULL) {
1880                         ldb_set_errstring(ldb, "Too many results");
1881                         talloc_free(ares);
1882                         return LDB_ERR_OPERATIONS_ERROR;
1883                 }
1884
1885                 /* if it is not an entry of type person this is an error */
1886                 /* TODO: remove this when userPassword will be in schema */
1887                 if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
1888                         ldb_set_errstring(ldb, "Object class violation");
1889                         talloc_free(ares);
1890                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
1891                 }
1892
1893                 ac->search_res = talloc_steal(ac, ares);
1894         } else {
1895                 talloc_free(ares);
1896         }
1897
1898         return LDB_SUCCESS;
1899 }
1900
1901 static int password_hash_mod_search_self(struct ldb_handle *h) {
1902
1903         struct ph_context *ac;
1904         static const char * const attrs[] = { "userAccountControl", "lmPwdHistory", 
1905                                               "ntPwdHistory", 
1906                                               "objectSid", "msDS-KeyVersionNumber", 
1907                                               "objectClass", "userPrincipalName",
1908                                               "sAMAccountName", 
1909                                               "dBCSPwd", "unicodePwd",
1910                                               "supplementalCredentials",
1911                                               NULL };
1912
1913         ac = talloc_get_type(h->private_data, struct ph_context);
1914
1915         /* prepare the search operation */
1916         ac->search_req = talloc_zero(ac, struct ldb_request);
1917         if (ac->search_req == NULL) {
1918                 ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
1919                 return LDB_ERR_OPERATIONS_ERROR;
1920         }
1921
1922         ac->search_req->operation = LDB_SEARCH;
1923         ac->search_req->op.search.base = ac->orig_req->op.mod.message->dn;
1924         ac->search_req->op.search.scope = LDB_SCOPE_BASE;
1925         ac->search_req->op.search.tree = ldb_parse_tree(ac->search_req, NULL);
1926         if (ac->search_req->op.search.tree == NULL) {
1927                 ldb_set_errstring(ac->module->ldb, "Invalid search filter");
1928                 return LDB_ERR_OPERATIONS_ERROR;
1929         }
1930         ac->search_req->op.search.attrs = attrs;
1931         ac->search_req->controls = NULL;
1932         ac->search_req->context = ac;
1933         ac->search_req->callback = get_self_callback;
1934         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
1935
1936         ac->step = PH_MOD_SEARCH_SELF;
1937
1938         return ldb_next_request(ac->module, ac->search_req);
1939 }
1940
1941 static int password_hash_mod_search_dom(struct ldb_handle *h) {
1942
1943         struct ph_context *ac;
1944         int ret;
1945
1946         ac = talloc_get_type(h->private_data, struct ph_context);
1947
1948         /* get object domain sid */
1949         ac->domain_sid = samdb_result_sid_prefix(ac, ac->search_res->message, "objectSid");
1950         if (ac->domain_sid == NULL) {
1951                 ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "can't handle entry with missing objectSid!\n");
1952                 return LDB_ERR_OPERATIONS_ERROR;
1953         }
1954
1955         /* get user domain data */
1956         ret = build_domain_data_request(ac);
1957         if (ret != LDB_SUCCESS) {
1958                 return ret;
1959         }
1960
1961         ac->step = PH_MOD_SEARCH_DOM;
1962
1963         return ldb_next_request(ac->module, ac->dom_req);
1964 }
1965
1966 static int password_hash_mod_do_mod(struct ldb_handle *h) {
1967
1968         struct ph_context *ac;
1969         struct domain_data *domain;
1970         struct smb_krb5_context *smb_krb5_context;
1971         struct ldb_message *msg;
1972         struct ldb_message *orig_msg;
1973         struct ldb_message *searched_msg;
1974         struct setup_password_fields_io io;
1975         int ret;
1976
1977         ac = talloc_get_type(h->private_data, struct ph_context);
1978
1979         domain = get_domain_data(ac->module, ac, ac->dom_res);
1980         if (domain == NULL) {
1981                 return LDB_ERR_OPERATIONS_ERROR;
1982         }
1983
1984         ac->mod_req = talloc(ac, struct ldb_request);
1985         if (ac->mod_req == NULL) {
1986                 return LDB_ERR_OPERATIONS_ERROR;
1987         }
1988
1989         *(ac->mod_req) = *(ac->orig_req);
1990         
1991         /* use a new message structure so that we can modify it */
1992         ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
1993         if (msg == NULL) {
1994                 return LDB_ERR_OPERATIONS_ERROR;
1995         }
1996
1997         /* modify dn */
1998         msg->dn = ac->orig_req->op.mod.message->dn;
1999
2000         /* Some operations below require kerberos contexts */
2001         if (smb_krb5_init_context(ac->mod_req, 
2002                                   ldb_get_opaque(h->module->ldb, "EventContext"), 
2003                                   (struct loadparm_context *)ldb_get_opaque(h->module->ldb, "loadparm"), 
2004                                   &smb_krb5_context) != 0) {
2005                 return LDB_ERR_OPERATIONS_ERROR;
2006         }
2007
2008         orig_msg        = discard_const(ac->orig_req->op.mod.message);
2009         searched_msg    = ac->search_res->message;
2010
2011         ZERO_STRUCT(io);
2012         io.ac                           = ac;
2013         io.domain                       = domain;
2014         io.smb_krb5_context             = smb_krb5_context;
2015
2016         io.u.user_account_control       = samdb_result_uint(searched_msg, "userAccountControl", 0);
2017         io.u.sAMAccountName             = samdb_result_string(searched_msg, "samAccountName", NULL);
2018         io.u.user_principal_name        = samdb_result_string(searched_msg, "userPrincipalName", NULL);
2019         io.u.is_computer                = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
2020
2021         io.n.cleartext                  = samdb_result_string(orig_msg, "userPassword", NULL);
2022         io.n.nt_hash                    = samdb_result_hash(io.ac, orig_msg, "unicodePwd");
2023         io.n.lm_hash                    = samdb_result_hash(io.ac, orig_msg, "dBCSPwd");
2024
2025         io.o.kvno                       = samdb_result_uint(searched_msg, "msDs-KeyVersionNumber", 0);
2026         io.o.nt_history_len             = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
2027         io.o.lm_history_len             = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
2028         io.o.supplemental               = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
2029
2030         ret = setup_password_fields(&io);
2031         if (ret != LDB_SUCCESS) {
2032                 return ret;
2033         }
2034
2035         /* make sure we replace all the old attributes */
2036         ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
2037         ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
2038         ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2039         ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2040         ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
2041         ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
2042         ret = ldb_msg_add_empty(msg, "msDs-KeyVersionNumber", LDB_FLAG_MOD_REPLACE, NULL);
2043
2044         if (io.g.nt_hash) {
2045                 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
2046                                          "unicodePwd", io.g.nt_hash);
2047                 if (ret != LDB_SUCCESS) {
2048                         return ret;
2049                 }
2050         }
2051         if (io.g.lm_hash) {
2052                 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
2053                                          "dBCSPwd", io.g.lm_hash);
2054                 if (ret != LDB_SUCCESS) {
2055                         return ret;
2056                 }
2057         }
2058         if (io.g.nt_history_len > 0) {
2059                 ret = samdb_msg_add_hashes(ac, msg,
2060                                            "ntPwdHistory",
2061                                            io.g.nt_history,
2062                                            io.g.nt_history_len);
2063                 if (ret != LDB_SUCCESS) {
2064                         return ret;
2065                 }
2066         }
2067         if (io.g.lm_history_len > 0) {
2068                 ret = samdb_msg_add_hashes(ac, msg,
2069                                            "lmPwdHistory",
2070                                            io.g.lm_history,
2071                                            io.g.lm_history_len);
2072                 if (ret != LDB_SUCCESS) {
2073                         return ret;
2074                 }
2075         }
2076         if (io.g.supplemental.length > 0) {
2077                 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2078                                         &io.g.supplemental, NULL);
2079                 if (ret != LDB_SUCCESS) {
2080                         return ret;
2081                 }
2082         }
2083         ret = samdb_msg_add_uint64(ac->module->ldb, ac, msg,
2084                                    "pwdLastSet",
2085                                    io.g.last_set);
2086         if (ret != LDB_SUCCESS) {
2087                 return ret;
2088         }
2089         ret = samdb_msg_add_uint(ac->module->ldb, ac, msg,
2090                                  "msDs-KeyVersionNumber",
2091                                  io.g.kvno);
2092         if (ret != LDB_SUCCESS) {
2093                 return ret;
2094         }
2095
2096         h->state = LDB_ASYNC_INIT;
2097         h->status = LDB_SUCCESS;
2098
2099         ac->step = PH_MOD_DO_MOD;
2100
2101         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req);
2102
2103         /* perform the search */
2104         return ldb_next_request(ac->module, ac->mod_req);
2105 }
2106
2107 static int ph_wait(struct ldb_handle *handle) {
2108         struct ph_context *ac;
2109         int ret;
2110     
2111         if (!handle || !handle->private_data) {
2112                 return LDB_ERR_OPERATIONS_ERROR;
2113         }
2114
2115         if (handle->state == LDB_ASYNC_DONE) {
2116                 return handle->status;
2117         }
2118
2119         handle->state = LDB_ASYNC_PENDING;
2120         handle->status = LDB_SUCCESS;
2121
2122         ac = talloc_get_type(handle->private_data, struct ph_context);
2123
2124         switch (ac->step) {
2125         case PH_ADD_SEARCH_DOM:
2126                 ret = ldb_wait(ac->dom_req->handle, LDB_WAIT_NONE);
2127
2128                 if (ret != LDB_SUCCESS) {
2129                         handle->status = ret;
2130                         goto done;
2131                 }
2132                 if (ac->dom_req->handle->status != LDB_SUCCESS) {
2133                         handle->status = ac->dom_req->handle->status;
2134                         goto done;
2135                 }
2136
2137                 if (ac->dom_req->handle->state != LDB_ASYNC_DONE) {
2138                         return LDB_SUCCESS;
2139                 }
2140
2141                 /* domain search done, go on */
2142                 return password_hash_add_do_add(handle);
2143
2144         case PH_ADD_DO_ADD:
2145                 ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
2146
2147                 if (ret != LDB_SUCCESS) {
2148                         handle->status = ret;
2149                         goto done;
2150                 }
2151                 if (ac->down_req->handle->status != LDB_SUCCESS) {
2152                         handle->status = ac->down_req->handle->status;
2153                         goto done;
2154                 }
2155
2156                 if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
2157                         return LDB_SUCCESS;
2158                 }
2159
2160                 break;
2161                 
2162         case PH_MOD_DO_REQ:
2163                 ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
2164
2165                 if (ret != LDB_SUCCESS) {
2166                         handle->status = ret;
2167                         goto done;
2168                 }
2169                 if (ac->down_req->handle->status != LDB_SUCCESS) {
2170                         handle->status = ac->down_req->handle->status;
2171                         goto done;
2172                 }
2173
2174                 if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
2175                         return LDB_SUCCESS;
2176                 }
2177
2178                 /* non-password mods done, go on */
2179                 return password_hash_mod_search_self(handle);
2180                 
2181         case PH_MOD_SEARCH_SELF:
2182                 ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
2183
2184                 if (ret != LDB_SUCCESS) {
2185                         handle->status = ret;
2186                         goto done;
2187                 }
2188                 if (ac->search_req->handle->status != LDB_SUCCESS) {
2189                         handle->status = ac->search_req->handle->status;
2190                         goto done;
2191                 }
2192
2193                 if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
2194                         return LDB_SUCCESS;
2195                 }
2196
2197                 if (ac->search_res == NULL) {
2198                         return LDB_ERR_NO_SUCH_OBJECT;
2199                 }
2200
2201                 /* self search done, go on */
2202                 return password_hash_mod_search_dom(handle);
2203                 
2204         case PH_MOD_SEARCH_DOM:
2205                 ret = ldb_wait(ac->dom_req->handle, LDB_WAIT_NONE);
2206
2207                 if (ret != LDB_SUCCESS) {
2208                         handle->status = ret;
2209                         goto done;
2210                 }
2211                 if (ac->dom_req->handle->status != LDB_SUCCESS) {
2212                         handle->status = ac->dom_req->handle->status;
2213                         goto done;
2214                 }
2215
2216                 if (ac->dom_req->handle->state != LDB_ASYNC_DONE) {
2217                         return LDB_SUCCESS;
2218                 }
2219
2220                 /* domain search done, go on */
2221                 return password_hash_mod_do_mod(handle);
2222
2223         case PH_MOD_DO_MOD:
2224                 ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
2225
2226                 if (ret != LDB_SUCCESS) {
2227                         handle->status = ret;
2228                         goto done;
2229                 }
2230                 if (ac->mod_req->handle->status != LDB_SUCCESS) {
2231                         handle->status = ac->mod_req->handle->status;
2232                         goto done;
2233                 }
2234
2235                 if (ac->mod_req->handle->state != LDB_ASYNC_DONE) {
2236                         return LDB_SUCCESS;
2237                 }
2238
2239                 break;
2240                 
2241         default:
2242                 ret = LDB_ERR_OPERATIONS_ERROR;
2243                 goto done;
2244         }
2245
2246         ret = LDB_SUCCESS;
2247
2248 done:
2249         handle->state = LDB_ASYNC_DONE;
2250         return ret;
2251 }
2252
2253 static int ph_wait_all(struct ldb_handle *handle) {
2254
2255         int ret;
2256
2257         while (handle->state != LDB_ASYNC_DONE) {
2258                 ret = ph_wait(handle);
2259                 if (ret != LDB_SUCCESS) {
2260                         return ret;
2261                 }
2262         }
2263
2264         return handle->status;
2265 }
2266
2267 static int password_hash_wait(struct ldb_handle *handle, enum ldb_wait_type type)
2268 {
2269         if (type == LDB_WAIT_ALL) {
2270                 return ph_wait_all(handle);
2271         } else {
2272                 return ph_wait(handle);
2273         }
2274 }
2275
2276 _PUBLIC_ const struct ldb_module_ops ldb_password_hash_module_ops = {
2277         .name          = "password_hash",
2278         .add           = password_hash_add,
2279         .modify        = password_hash_modify,
2280         .wait          = password_hash_wait
2281 };