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