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