s4:dsdb/password_hash: reject interdomain trust password changes via LDAP
[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 = talloc_get_type(
2231                 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
2232         int ret;
2233
2234         ZERO_STRUCTP(io);
2235
2236         /* Some operations below require kerberos contexts */
2237
2238         if (smb_krb5_init_context(ac,
2239                                   (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
2240                                   &io->smb_krb5_context) != 0) {
2241                 return ldb_operr(ldb);
2242         }
2243
2244         io->ac                          = ac;
2245
2246         io->u.userAccountControl        = ldb_msg_find_attr_as_uint(searched_msg,
2247                                                                     "userAccountControl", 0);
2248         io->u.pwdLastSet                = samdb_result_nttime(searched_msg, "pwdLastSet", 0);
2249         io->u.sAMAccountName            = ldb_msg_find_attr_as_string(searched_msg,
2250                                                                       "sAMAccountName", NULL);
2251         io->u.user_principal_name       = ldb_msg_find_attr_as_string(searched_msg,
2252                                                                       "userPrincipalName", NULL);
2253         io->u.is_computer               = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
2254
2255         if (io->u.sAMAccountName == NULL) {
2256                 ldb_asprintf_errstring(ldb,
2257                                        "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
2258                                        ldb_dn_get_linearized(searched_msg->dn));
2259
2260                 return LDB_ERR_CONSTRAINT_VIOLATION;
2261         }
2262
2263         if (io->u.userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
2264                 struct ldb_control *permit_trust = ldb_request_get_control(ac->req,
2265                                 DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID);
2266
2267                 if (permit_trust == NULL) {
2268                         ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2269                         ldb_asprintf_errstring(ldb,
2270                                 "%08X: %s - setup_io: changing the interdomain trust password "
2271                                 "on %s not allowed via LDAP. Use LSA or NETLOGON",
2272                                 W_ERROR_V(WERR_ACCESS_DENIED),
2273                                 ldb_strerror(ret),
2274                                 ldb_dn_get_linearized(searched_msg->dn));
2275                         return ret;
2276                 }
2277         }
2278
2279         /* Only non-trust accounts have restrictions (possibly this test is the
2280          * wrong way around, but we like to be restrictive if possible */
2281         io->u.restrictions = !(io->u.userAccountControl
2282                 & (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
2283                         | UF_SERVER_TRUST_ACCOUNT));
2284
2285         if (ac->userPassword) {
2286                 ret = msg_find_old_and_new_pwd_val(orig_msg, "userPassword",
2287                                                    ac->req->operation,
2288                                                    &io->n.cleartext_utf8,
2289                                                    &io->og.cleartext_utf8);
2290                 if (ret != LDB_SUCCESS) {
2291                         ldb_asprintf_errstring(ldb,
2292                                 "setup_io: "
2293                                 "it's only allowed to set the old password once!");
2294                         return ret;
2295                 }
2296         }
2297
2298         if (io->n.cleartext_utf8 != NULL) {
2299                 struct ldb_val *cleartext_utf8_blob;
2300                 char *p;
2301
2302                 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
2303                 if (!cleartext_utf8_blob) {
2304                         return ldb_oom(ldb);
2305                 }
2306
2307                 *cleartext_utf8_blob = *io->n.cleartext_utf8;
2308
2309                 /* make sure we have a null terminated string */
2310                 p = talloc_strndup(cleartext_utf8_blob,
2311                                    (const char *)io->n.cleartext_utf8->data,
2312                                    io->n.cleartext_utf8->length);
2313                 if ((p == NULL) && (io->n.cleartext_utf8->length > 0)) {
2314                         return ldb_oom(ldb);
2315                 }
2316                 cleartext_utf8_blob->data = (uint8_t *)p;
2317
2318                 io->n.cleartext_utf8 = cleartext_utf8_blob;
2319         }
2320
2321         ret = msg_find_old_and_new_pwd_val(orig_msg, "clearTextPassword",
2322                                            ac->req->operation,
2323                                            &io->n.cleartext_utf16,
2324                                            &io->og.cleartext_utf16);
2325         if (ret != LDB_SUCCESS) {
2326                 ldb_asprintf_errstring(ldb,
2327                         "setup_io: "
2328                         "it's only allowed to set the old password once!");
2329                 return ret;
2330         }
2331
2332         /* this rather strange looking piece of code is there to
2333            handle a ldap client setting a password remotely using the
2334            unicodePwd ldap field. The syntax is that the password is
2335            in UTF-16LE, with a " at either end. Unfortunately the
2336            unicodePwd field is also used to store the nt hashes
2337            internally in Samba, and is used in the nt hash format on
2338            the wire in DRS replication, so we have a single name for
2339            two distinct values. The code below leaves us with a small
2340            chance (less than 1 in 2^32) of a mixup, if someone manages
2341            to create a MD4 hash which starts and ends in 0x22 0x00, as
2342            that would then be treated as a UTF16 password rather than
2343            a nthash */
2344
2345         ret = msg_find_old_and_new_pwd_val(orig_msg, "unicodePwd",
2346                                            ac->req->operation,
2347                                            &quoted_utf16,
2348                                            &old_quoted_utf16);
2349         if (ret != LDB_SUCCESS) {
2350                 ldb_asprintf_errstring(ldb,
2351                         "setup_io: "
2352                         "it's only allowed to set the old password once!");
2353                 return ret;
2354         }
2355
2356         /* Checks and converts the actual "unicodePwd" attribute */
2357         if (!ac->hash_values &&
2358             quoted_utf16 &&
2359             quoted_utf16->length >= 4 &&
2360             quoted_utf16->data[0] == '"' &&
2361             quoted_utf16->data[1] == 0 &&
2362             quoted_utf16->data[quoted_utf16->length-2] == '"' &&
2363             quoted_utf16->data[quoted_utf16->length-1] == 0) {
2364                 struct ldb_val *quoted_utf16_2;
2365
2366                 if (io->n.cleartext_utf16) {
2367                         /* refuse the change if someone wants to change with
2368                            with both UTF16 possibilities at the same time... */
2369                         ldb_asprintf_errstring(ldb,
2370                                 "setup_io: "
2371                                 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
2372                         return LDB_ERR_UNWILLING_TO_PERFORM;
2373                 }
2374
2375                 /*
2376                  * adapt the quoted UTF16 string to be a real
2377                  * cleartext one
2378                  */
2379                 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
2380                 if (quoted_utf16_2 == NULL) {
2381                         return ldb_oom(ldb);
2382                 }
2383
2384                 quoted_utf16_2->data = quoted_utf16->data + 2;
2385                 quoted_utf16_2->length = quoted_utf16->length-4;
2386                 io->n.cleartext_utf16 = quoted_utf16_2;
2387                 io->n.nt_hash = NULL;
2388
2389         } else if (quoted_utf16) {
2390                 /* We have only the hash available -> so no plaintext here */
2391                 if (!ac->hash_values) {
2392                         /* refuse the change if someone wants to change
2393                            the hash without control specified... */
2394                         ldb_asprintf_errstring(ldb,
2395                                 "setup_io: "
2396                                 "it's not allowed to set the NT hash password directly'");
2397                         /* this looks odd but this is what Windows does:
2398                            returns "UNWILLING_TO_PERFORM" on wrong
2399                            password sets and "CONSTRAINT_VIOLATION" on
2400                            wrong password changes. */
2401                         if (old_quoted_utf16 == NULL) {
2402                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2403                         }
2404
2405                         return LDB_ERR_CONSTRAINT_VIOLATION;
2406                 }
2407
2408                 io->n.nt_hash = talloc(io->ac, struct samr_Password);
2409                 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
2410                        MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
2411         }
2412
2413         /* Checks and converts the previous "unicodePwd" attribute */
2414         if (!ac->hash_values &&
2415             old_quoted_utf16 &&
2416             old_quoted_utf16->length >= 4 &&
2417             old_quoted_utf16->data[0] == '"' &&
2418             old_quoted_utf16->data[1] == 0 &&
2419             old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
2420             old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
2421                 struct ldb_val *old_quoted_utf16_2;
2422
2423                 if (io->og.cleartext_utf16) {
2424                         /* refuse the change if someone wants to change with
2425                            both UTF16 possibilities at the same time... */
2426                         ldb_asprintf_errstring(ldb,
2427                                 "setup_io: "
2428                                 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
2429                         return LDB_ERR_UNWILLING_TO_PERFORM;
2430                 }
2431
2432                 /*
2433                  * adapt the quoted UTF16 string to be a real
2434                  * cleartext one
2435                  */
2436                 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
2437                 if (old_quoted_utf16_2 == NULL) {
2438                         return ldb_oom(ldb);
2439                 }
2440
2441                 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
2442                 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
2443
2444                 io->og.cleartext_utf16 = old_quoted_utf16_2;
2445                 io->og.nt_hash = NULL;
2446         } else if (old_quoted_utf16) {
2447                 /* We have only the hash available -> so no plaintext here */
2448                 if (!ac->hash_values) {
2449                         /* refuse the change if someone wants to change
2450                            the hash without control specified... */
2451                         ldb_asprintf_errstring(ldb,
2452                                 "setup_io: "
2453                                 "it's not allowed to set the NT hash password directly'");
2454                         return LDB_ERR_UNWILLING_TO_PERFORM;
2455                 }
2456
2457                 io->og.nt_hash = talloc(io->ac, struct samr_Password);
2458                 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
2459                        MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
2460         }
2461
2462         /* Handles the "dBCSPwd" attribute (LM hash) */
2463         io->n.lm_hash = NULL; io->og.lm_hash = NULL;
2464         ret = msg_find_old_and_new_pwd_val(orig_msg, "dBCSPwd",
2465                                            ac->req->operation,
2466                                            &lm_hash, &old_lm_hash);
2467         if (ret != LDB_SUCCESS) {
2468                 ldb_asprintf_errstring(ldb,
2469                         "setup_io: "
2470                         "it's only allowed to set the old password once!");
2471                 return ret;
2472         }
2473
2474         if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
2475                 /* refuse the change if someone wants to change the hash
2476                    without control specified... */
2477                 ldb_asprintf_errstring(ldb,
2478                         "setup_io: "
2479                         "it's not allowed to set the LM hash password directly'");
2480                 return LDB_ERR_UNWILLING_TO_PERFORM;
2481         }
2482
2483         if (lpcfg_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
2484                 io->n.lm_hash = talloc(io->ac, struct samr_Password);
2485                 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
2486                        sizeof(io->n.lm_hash->hash)));
2487         }
2488         if (lpcfg_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
2489                 io->og.lm_hash = talloc(io->ac, struct samr_Password);
2490                 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
2491                        sizeof(io->og.lm_hash->hash)));
2492         }
2493
2494         /*
2495          * Handles the password change control if it's specified. It has the
2496          * precedance and overrides already specified old password values of
2497          * change requests (but that shouldn't happen since the control is
2498          * fully internal and only used in conjunction with replace requests!).
2499          */
2500         if (ac->change != NULL) {
2501                 io->og.nt_hash = NULL;
2502                 if (ac->change->old_nt_pwd_hash != NULL) {
2503                         io->og.nt_hash = talloc_memdup(io->ac,
2504                                                        ac->change->old_nt_pwd_hash,
2505                                                        sizeof(struct samr_Password));
2506                 }
2507                 io->og.lm_hash = NULL;
2508                 if (lpcfg_lanman_auth(lp_ctx) && (ac->change->old_lm_pwd_hash != NULL)) {
2509                         io->og.lm_hash = talloc_memdup(io->ac,
2510                                                        ac->change->old_lm_pwd_hash,
2511                                                        sizeof(struct samr_Password));
2512                 }
2513         }
2514
2515         /* refuse the change if someone wants to change the clear-
2516            text and supply his own hashes at the same time... */
2517         if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
2518                         && (io->n.nt_hash || io->n.lm_hash)) {
2519                 ldb_asprintf_errstring(ldb,
2520                         "setup_io: "
2521                         "it's only allowed to set the password in form of cleartext attributes or as hashes");
2522                 return LDB_ERR_UNWILLING_TO_PERFORM;
2523         }
2524
2525         /* refuse the change if someone wants to change the password
2526            using both plaintext methods (UTF8 and UTF16) at the same time... */
2527         if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
2528                 ldb_asprintf_errstring(ldb,
2529                         "setup_io: "
2530                         "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
2531                 return LDB_ERR_UNWILLING_TO_PERFORM;
2532         }
2533
2534         /* refuse the change if someone tries to set/change the password by
2535          * the lanman hash alone and we've deactivated that mechanism. This
2536          * would end in an account without any password! */
2537         if ((!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
2538             && (!io->n.nt_hash) && (!io->n.lm_hash)) {
2539                 ldb_asprintf_errstring(ldb,
2540                         "setup_io: "
2541                         "It' not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!");
2542                 /* on "userPassword" and "clearTextPassword" we've to return
2543                  * something different, since these are virtual attributes */
2544                 if ((ldb_msg_find_element(orig_msg, "userPassword") != NULL) ||
2545                     (ldb_msg_find_element(orig_msg, "clearTextPassword") != NULL)) {
2546                         return LDB_ERR_CONSTRAINT_VIOLATION;
2547                 }
2548                 return LDB_ERR_UNWILLING_TO_PERFORM;
2549         }
2550
2551         /* refuse the change if someone wants to compare against a plaintext
2552            or hash at the same time for a "password modify" operation... */
2553         if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
2554             && (io->og.nt_hash || io->og.lm_hash)) {
2555                 ldb_asprintf_errstring(ldb,
2556                         "setup_io: "
2557                         "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
2558                 return LDB_ERR_UNWILLING_TO_PERFORM;
2559         }
2560
2561         /* refuse the change if someone wants to compare against both
2562          * plaintexts at the same time for a "password modify" operation... */
2563         if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
2564                 ldb_asprintf_errstring(ldb,
2565                         "setup_io: "
2566                         "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
2567                 return LDB_ERR_UNWILLING_TO_PERFORM;
2568         }
2569
2570         /* Decides if we have a password modify or password reset operation */
2571         if (ac->req->operation == LDB_ADD) {
2572                 /* On "add" we have only "password reset" */
2573                 ac->pwd_reset = true;
2574         } else if (ac->req->operation == LDB_MODIFY) {
2575                 if (io->og.cleartext_utf8 || io->og.cleartext_utf16
2576                     || io->og.nt_hash || io->og.lm_hash) {
2577                         /* If we have an old password specified then for sure it
2578                          * is a user "password change" */
2579                         ac->pwd_reset = false;
2580                 } else {
2581                         /* Otherwise we have also here a "password reset" */
2582                         ac->pwd_reset = true;
2583                 }
2584         } else {
2585                 /* this shouldn't happen */
2586                 return ldb_operr(ldb);
2587         }
2588
2589         return LDB_SUCCESS;
2590 }
2591
2592 static struct ph_context *ph_init_context(struct ldb_module *module,
2593                                           struct ldb_request *req,
2594                                           bool userPassword)
2595 {
2596         struct ldb_context *ldb;
2597         struct ph_context *ac;
2598
2599         ldb = ldb_module_get_ctx(module);
2600
2601         ac = talloc_zero(req, struct ph_context);
2602         if (ac == NULL) {
2603                 ldb_set_errstring(ldb, "Out of Memory");
2604                 return NULL;
2605         }
2606
2607         ac->module = module;
2608         ac->req = req;
2609         ac->userPassword = userPassword;
2610
2611         return ac;
2612 }
2613
2614 static void ph_apply_controls(struct ph_context *ac)
2615 {
2616         struct ldb_control *ctrl;
2617
2618         ac->change_status = false;
2619         ctrl = ldb_request_get_control(ac->req,
2620                                        DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
2621         if (ctrl != NULL) {
2622                 ac->change_status = true;
2623
2624                 /* Mark the "change status" control as uncritical (done) */
2625                 ctrl->critical = false;
2626         }
2627
2628         ac->hash_values = false;
2629         ctrl = ldb_request_get_control(ac->req,
2630                                        DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
2631         if (ctrl != NULL) {
2632                 ac->hash_values = true;
2633
2634                 /* Mark the "hash values" control as uncritical (done) */
2635                 ctrl->critical = false;
2636         }
2637
2638         ctrl = ldb_request_get_control(ac->req,
2639                                        DSDB_CONTROL_PASSWORD_CHANGE_OID);
2640         if (ctrl != NULL) {
2641                 ac->change = (struct dsdb_control_password_change *) ctrl->data;
2642
2643                 /* Mark the "change" control as uncritical (done) */
2644                 ctrl->critical = false;
2645         }
2646
2647         ac->pwd_last_set_bypass = false;
2648         ctrl = ldb_request_get_control(ac->req,
2649                                 DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID);
2650         if (ctrl != NULL) {
2651                 ac->pwd_last_set_bypass = true;
2652
2653                 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
2654                 ctrl->critical = false;
2655         }
2656 }
2657
2658 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
2659 {
2660         struct ph_context *ac;
2661
2662         ac = talloc_get_type(req->context, struct ph_context);
2663
2664         if (!ares) {
2665                 return ldb_module_done(ac->req, NULL, NULL,
2666                                         LDB_ERR_OPERATIONS_ERROR);
2667         }
2668
2669         if (ares->type == LDB_REPLY_REFERRAL) {
2670                 return ldb_module_send_referral(ac->req, ares->referral);
2671         }
2672
2673         if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2674                 /* On success and trivial errors a status control is being
2675                  * added (used for example by the "samdb_set_password" call) */
2676                 ldb_reply_add_control(ares,
2677                                       DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2678                                       false,
2679                                       ac->status);
2680         }
2681
2682         if (ares->error != LDB_SUCCESS) {
2683                 return ldb_module_done(ac->req, ares->controls,
2684                                         ares->response, ares->error);
2685         }
2686
2687         if (ares->type != LDB_REPLY_DONE) {
2688                 talloc_free(ares);
2689                 return ldb_module_done(ac->req, NULL, NULL,
2690                                         LDB_ERR_OPERATIONS_ERROR);
2691         }
2692
2693         return ldb_module_done(ac->req, ares->controls,
2694                                 ares->response, ares->error);
2695 }
2696
2697 static int password_hash_add_do_add(struct ph_context *ac);
2698 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
2699 static int password_hash_mod_search_self(struct ph_context *ac);
2700 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
2701 static int password_hash_mod_do_mod(struct ph_context *ac);
2702
2703 static int get_domain_data_callback(struct ldb_request *req,
2704                                     struct ldb_reply *ares)
2705 {
2706         struct ldb_context *ldb;
2707         struct ph_context *ac;
2708         struct loadparm_context *lp_ctx;
2709         int ret = LDB_SUCCESS;
2710
2711         ac = talloc_get_type(req->context, struct ph_context);
2712         ldb = ldb_module_get_ctx(ac->module);
2713
2714         if (!ares) {
2715                 ret = LDB_ERR_OPERATIONS_ERROR;
2716                 goto done;
2717         }
2718         if (ares->error != LDB_SUCCESS) {
2719                 return ldb_module_done(ac->req, ares->controls,
2720                                         ares->response, ares->error);
2721         }
2722
2723         switch (ares->type) {
2724         case LDB_REPLY_ENTRY:
2725                 if (ac->status != NULL) {
2726                         talloc_free(ares);
2727
2728                         ldb_set_errstring(ldb, "Too many results");
2729                         ret = LDB_ERR_OPERATIONS_ERROR;
2730                         goto done;
2731                 }
2732
2733                 /* Setup the "status" structure (used as control later) */
2734                 ac->status = talloc_zero(ac->req,
2735                                          struct dsdb_control_password_change_status);
2736                 if (ac->status == NULL) {
2737                         talloc_free(ares);
2738
2739                         ldb_oom(ldb);
2740                         ret = LDB_ERR_OPERATIONS_ERROR;
2741                         goto done;
2742                 }
2743
2744                 /* Setup the "domain data" structure */
2745                 ac->status->domain_data.pwdProperties =
2746                         ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
2747                 ac->status->domain_data.pwdHistoryLength =
2748                         ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
2749                 ac->status->domain_data.maxPwdAge =
2750                         ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
2751                 ac->status->domain_data.minPwdAge =
2752                         ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
2753                 ac->status->domain_data.minPwdLength =
2754                         ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
2755                 ac->status->domain_data.store_cleartext =
2756                         ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
2757
2758                 /* For a domain DN, this puts things in dotted notation */
2759                 /* For builtin domains, this will give details for the host,
2760                  * but that doesn't really matter, as it's just used for salt
2761                  * and kerberos principals, which don't exist here */
2762
2763                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2764                                          struct loadparm_context);
2765
2766                 ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
2767                 ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
2768                 ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
2769
2770                 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2771
2772                 if (ac->dom_res != NULL) {
2773                         talloc_free(ares);
2774
2775                         ldb_set_errstring(ldb, "Too many results");
2776                         ret = LDB_ERR_OPERATIONS_ERROR;
2777                         goto done;
2778                 }
2779
2780                 ac->dom_res = talloc_steal(ac, ares);
2781                 ret = LDB_SUCCESS;
2782                 break;
2783
2784         case LDB_REPLY_REFERRAL:
2785                 /* ignore */
2786                 talloc_free(ares);
2787                 ret = LDB_SUCCESS;
2788                 break;
2789
2790         case LDB_REPLY_DONE:
2791                 talloc_free(ares);
2792                 /* call the next step */
2793                 switch (ac->req->operation) {
2794                 case LDB_ADD:
2795                         ret = password_hash_add_do_add(ac);
2796                         break;
2797
2798                 case LDB_MODIFY:
2799                         ret = password_hash_mod_do_mod(ac);
2800                         break;
2801
2802                 default:
2803                         ret = LDB_ERR_OPERATIONS_ERROR;
2804                         break;
2805                 }
2806                 break;
2807         }
2808
2809 done:
2810         if (ret != LDB_SUCCESS) {
2811                 struct ldb_reply *new_ares;
2812
2813                 new_ares = talloc_zero(ac->req, struct ldb_reply);
2814                 if (new_ares == NULL) {
2815                         ldb_oom(ldb);
2816                         return ldb_module_done(ac->req, NULL, NULL,
2817                                                LDB_ERR_OPERATIONS_ERROR);
2818                 }
2819
2820                 new_ares->error = ret;
2821                 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2822                         /* On success and trivial errors a status control is being
2823                          * added (used for example by the "samdb_set_password" call) */
2824                         ldb_reply_add_control(new_ares,
2825                                               DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2826                                               false,
2827                                               ac->status);
2828                 }
2829
2830                 return ldb_module_done(ac->req, new_ares->controls,
2831                                        new_ares->response, new_ares->error);
2832         }
2833
2834         return LDB_SUCCESS;
2835 }
2836
2837 static int build_domain_data_request(struct ph_context *ac)
2838 {
2839         /* attrs[] is returned from this function in
2840            ac->dom_req->op.search.attrs, so it must be static, as
2841            otherwise the compiler can put it on the stack */
2842         struct ldb_context *ldb;
2843         static const char * const attrs[] = { "pwdProperties",
2844                                               "pwdHistoryLength",
2845                                               "maxPwdAge",
2846                                               "minPwdAge",
2847                                               "minPwdLength",
2848                                               "lockoutThreshold",
2849                                               "lockOutObservationWindow",
2850                                               NULL };
2851         int ret;
2852
2853         ldb = ldb_module_get_ctx(ac->module);
2854
2855         ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
2856                                    ldb_get_default_basedn(ldb),
2857                                    LDB_SCOPE_BASE,
2858                                    NULL, attrs,
2859                                    NULL,
2860                                    ac, get_domain_data_callback,
2861                                    ac->req);
2862         LDB_REQ_SET_LOCATION(ac->dom_req);
2863         return ret;
2864 }
2865
2866 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
2867 {
2868         struct ldb_context *ldb;
2869         struct ph_context *ac;
2870         struct ldb_message_element *userPasswordAttr, *clearTextPasswordAttr,
2871                 *ntAttr, *lmAttr;
2872         int ret;
2873         struct ldb_control *bypass = NULL;
2874         bool userPassword = dsdb_user_password_support(module, req, req);
2875
2876         ldb = ldb_module_get_ctx(module);
2877
2878         ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
2879
2880         if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
2881                 return ldb_next_request(module, req);
2882         }
2883
2884         bypass = ldb_request_get_control(req,
2885                                          DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
2886         if (bypass != NULL) {
2887                 /* Mark the "bypass" control as uncritical (done) */
2888                 bypass->critical = false;
2889                 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add (bypassing)\n");
2890                 return password_hash_bypass(module, req);
2891         }
2892
2893         /* nobody must touch password histories and 'supplementalCredentials' */
2894         if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
2895                 return LDB_ERR_UNWILLING_TO_PERFORM;
2896         }
2897         if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
2898                 return LDB_ERR_UNWILLING_TO_PERFORM;
2899         }
2900         if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
2901                 return LDB_ERR_UNWILLING_TO_PERFORM;
2902         }
2903
2904         /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
2905          * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes. */
2906
2907         userPasswordAttr = NULL;
2908         if (userPassword) {
2909                 userPasswordAttr = ldb_msg_find_element(req->op.add.message,
2910                                                         "userPassword");
2911                 /* MS-ADTS 3.1.1.3.1.5.2 */
2912                 if ((userPasswordAttr != NULL) &&
2913                     (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
2914                         return LDB_ERR_CONSTRAINT_VIOLATION;
2915                 }
2916         }
2917         clearTextPasswordAttr = ldb_msg_find_element(req->op.add.message, "clearTextPassword");
2918         ntAttr = ldb_msg_find_element(req->op.add.message, "unicodePwd");
2919         lmAttr = ldb_msg_find_element(req->op.add.message, "dBCSPwd");
2920
2921         if ((!userPasswordAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
2922                 return ldb_next_request(module, req);
2923         }
2924
2925         /* Make sure we are performing the password set action on a (for us)
2926          * valid object. Those are instances of either "user" and/or
2927          * "inetOrgPerson". Otherwise continue with the submodules. */
2928         if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
2929                 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
2930
2931                 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
2932                         ldb_set_errstring(ldb,
2933                                           "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
2934                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
2935                 }
2936
2937                 return ldb_next_request(module, req);
2938         }
2939
2940         ac = ph_init_context(module, req, userPassword);
2941         if (ac == NULL) {
2942                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
2943                 return ldb_operr(ldb);
2944         }
2945         ph_apply_controls(ac);
2946
2947         /* get user domain data */
2948         ret = build_domain_data_request(ac);
2949         if (ret != LDB_SUCCESS) {
2950                 return ret;
2951         }
2952
2953         return ldb_next_request(module, ac->dom_req);
2954 }
2955
2956 static int password_hash_add_do_add(struct ph_context *ac)
2957 {
2958         struct ldb_context *ldb;
2959         struct ldb_request *down_req;
2960         struct ldb_message *msg;
2961         struct setup_password_fields_io io;
2962         int ret;
2963
2964         /* Prepare the internal data structure containing the passwords */
2965         ret = setup_io(ac, ac->req->op.add.message, ac->req->op.add.message, &io);
2966         if (ret != LDB_SUCCESS) {
2967                 return ret;
2968         }
2969
2970         ldb = ldb_module_get_ctx(ac->module);
2971
2972         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
2973         if (msg == NULL) {
2974                 return ldb_operr(ldb);
2975         }
2976
2977         /* remove attributes that we just read into 'io' */
2978         if (ac->userPassword) {
2979                 ldb_msg_remove_attr(msg, "userPassword");
2980         }
2981         ldb_msg_remove_attr(msg, "clearTextPassword");
2982         ldb_msg_remove_attr(msg, "unicodePwd");
2983         ldb_msg_remove_attr(msg, "dBCSPwd");
2984         ldb_msg_remove_attr(msg, "pwdLastSet");
2985
2986         ret = setup_password_fields(&io);
2987         if (ret != LDB_SUCCESS) {
2988                 return ret;
2989         }
2990
2991         ret = check_password_restrictions(&io);
2992         if (ret != LDB_SUCCESS) {
2993                 return ret;
2994         }
2995
2996         if (io.g.nt_hash) {
2997                 ret = samdb_msg_add_hash(ldb, ac, msg,
2998                                          "unicodePwd", io.g.nt_hash);
2999                 if (ret != LDB_SUCCESS) {
3000                         return ret;
3001                 }
3002         }
3003         if (io.g.lm_hash) {
3004                 ret = samdb_msg_add_hash(ldb, ac, msg,
3005                                          "dBCSPwd", io.g.lm_hash);
3006                 if (ret != LDB_SUCCESS) {
3007                         return ret;
3008                 }
3009         }
3010         if (io.g.nt_history_len > 0) {
3011                 ret = samdb_msg_add_hashes(ldb, ac, msg,
3012                                            "ntPwdHistory",
3013                                            io.g.nt_history,
3014                                            io.g.nt_history_len);
3015                 if (ret != LDB_SUCCESS) {
3016                         return ret;
3017                 }
3018         }
3019         if (io.g.lm_history_len > 0) {
3020                 ret = samdb_msg_add_hashes(ldb, ac, msg,
3021                                            "lmPwdHistory",
3022                                            io.g.lm_history,
3023                                            io.g.lm_history_len);
3024                 if (ret != LDB_SUCCESS) {
3025                         return ret;
3026                 }
3027         }
3028         if (io.g.supplemental.length > 0) {
3029                 ret = ldb_msg_add_value(msg, "supplementalCredentials",
3030                                         &io.g.supplemental, NULL);
3031                 if (ret != LDB_SUCCESS) {
3032                         return ret;
3033                 }
3034         }
3035         ret = samdb_msg_add_uint64(ldb, ac, msg,
3036                                    "pwdLastSet",
3037                                    io.g.last_set);
3038         if (ret != LDB_SUCCESS) {
3039                 return ret;
3040         }
3041
3042         ret = ldb_build_add_req(&down_req, ldb, ac,
3043                                 msg,
3044                                 ac->req->controls,
3045                                 ac, ph_op_callback,
3046                                 ac->req);
3047         LDB_REQ_SET_LOCATION(down_req);
3048         if (ret != LDB_SUCCESS) {
3049                 return ret;
3050         }
3051
3052         return ldb_next_request(ac->module, down_req);
3053 }
3054
3055 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
3056 {
3057         struct ldb_context *ldb;
3058         struct ph_context *ac;
3059         const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
3060                 "unicodePwd", "dBCSPwd", NULL }, **l;
3061         unsigned int attr_cnt, del_attr_cnt, add_attr_cnt, rep_attr_cnt;
3062         struct ldb_message_element *passwordAttr;
3063         struct ldb_message *msg;
3064         struct ldb_request *down_req;
3065         int ret;
3066         struct ldb_control *bypass = NULL;
3067         bool userPassword = dsdb_user_password_support(module, req, req);
3068
3069         ldb = ldb_module_get_ctx(module);
3070
3071         ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
3072
3073         if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
3074                 return ldb_next_request(module, req);
3075         }
3076         
3077         bypass = ldb_request_get_control(req,
3078                                          DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
3079         if (bypass != NULL) {
3080                 /* Mark the "bypass" control as uncritical (done) */
3081                 bypass->critical = false;
3082                 ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify (bypassing)\n");
3083                 return password_hash_bypass(module, req);
3084         }
3085
3086         /* nobody must touch password histories and 'supplementalCredentials' */
3087         if (ldb_msg_find_element(req->op.mod.message, "ntPwdHistory")) {
3088                 return LDB_ERR_UNWILLING_TO_PERFORM;
3089         }
3090         if (ldb_msg_find_element(req->op.mod.message, "lmPwdHistory")) {
3091                 return LDB_ERR_UNWILLING_TO_PERFORM;
3092         }
3093         if (ldb_msg_find_element(req->op.mod.message, "supplementalCredentials")) {
3094                 return LDB_ERR_UNWILLING_TO_PERFORM;
3095         }
3096
3097         /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
3098          * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
3099          * For password changes/set there should be a 'delete' or a 'modify'
3100          * on these attributes. */
3101         attr_cnt = 0;
3102         for (l = passwordAttrs; *l != NULL; l++) {
3103                 if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
3104                         continue;
3105                 }
3106
3107                 if (ldb_msg_find_element(req->op.mod.message, *l) != NULL) {
3108                         /* MS-ADTS 3.1.1.3.1.5.2 */
3109                         if ((ldb_attr_cmp(*l, "userPassword") == 0) &&
3110                             (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
3111                                 return LDB_ERR_CONSTRAINT_VIOLATION;
3112                         }
3113
3114                         ++attr_cnt;
3115                 }
3116         }
3117         if (attr_cnt == 0) {
3118                 return ldb_next_request(module, req);
3119         }
3120
3121         ac = ph_init_context(module, req, userPassword);
3122         if (!ac) {
3123                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3124                 return ldb_operr(ldb);
3125         }
3126         ph_apply_controls(ac);
3127
3128         /* use a new message structure so that we can modify it */
3129         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3130         if (msg == NULL) {
3131                 return ldb_oom(ldb);
3132         }
3133
3134         /* - check for single-valued password attributes
3135          *   (if not return "CONSTRAINT_VIOLATION")
3136          * - check that for a password change operation one add and one delete
3137          *   operation exists
3138          *   (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
3139          * - check that a password change and a password set operation cannot
3140          *   be mixed
3141          *   (if not return "UNWILLING_TO_PERFORM")
3142          * - remove all password attributes modifications from the first change
3143          *   operation (anything without the passwords) - we will make the real
3144          *   modification later */
3145         del_attr_cnt = 0;
3146         add_attr_cnt = 0;
3147         rep_attr_cnt = 0;
3148         for (l = passwordAttrs; *l != NULL; l++) {
3149                 if ((!ac->userPassword) &&
3150                     (ldb_attr_cmp(*l, "userPassword") == 0)) {
3151                         continue;
3152                 }
3153
3154                 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
3155                         if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE) {
3156                                 ++del_attr_cnt;
3157                         }
3158                         if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD) {
3159                                 ++add_attr_cnt;
3160                         }
3161                         if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_REPLACE) {
3162                                 ++rep_attr_cnt;
3163                         }
3164                         if ((passwordAttr->num_values != 1) &&
3165                             (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD)) {
3166                                 talloc_free(ac);
3167                                 ldb_asprintf_errstring(ldb,
3168                                                        "'%s' attribute must have exactly one value on add operations!",
3169                                                        *l);
3170                                 return LDB_ERR_CONSTRAINT_VIOLATION;
3171                         }
3172                         if ((passwordAttr->num_values > 1) &&
3173                             (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE)) {
3174                                 talloc_free(ac);
3175                                 ldb_asprintf_errstring(ldb,
3176                                                        "'%s' attribute must have zero or one value(s) on delete operations!",
3177                                                        *l);
3178                                 return LDB_ERR_CONSTRAINT_VIOLATION;
3179                         }
3180                         ldb_msg_remove_element(msg, passwordAttr);
3181                 }
3182         }
3183         if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
3184                 talloc_free(ac);
3185                 ldb_set_errstring(ldb,
3186                                   "Only the add action for a password change specified!");
3187                 return LDB_ERR_UNWILLING_TO_PERFORM;
3188         }
3189         if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
3190                 talloc_free(ac);
3191                 ldb_set_errstring(ldb,
3192                                   "Only one delete and one add action for a password change allowed!");
3193                 return LDB_ERR_UNWILLING_TO_PERFORM;
3194         }
3195         if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
3196                 talloc_free(ac);
3197                 ldb_set_errstring(ldb,
3198                                   "Either a password change or a password set operation is allowed!");
3199                 return LDB_ERR_UNWILLING_TO_PERFORM;
3200         }
3201
3202         /* if there was nothing else to be modified skip to next step */
3203         if (msg->num_elements == 0) {
3204                 return password_hash_mod_search_self(ac);
3205         }
3206
3207         ret = ldb_build_mod_req(&down_req, ldb, ac,
3208                                 msg,
3209                                 req->controls,
3210                                 ac, ph_modify_callback,
3211                                 req);
3212         LDB_REQ_SET_LOCATION(down_req);
3213         if (ret != LDB_SUCCESS) {
3214                 return ret;
3215         }
3216
3217         return ldb_next_request(module, down_req);
3218 }
3219
3220 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3221 {
3222         struct ph_context *ac;
3223
3224         ac = talloc_get_type(req->context, struct ph_context);
3225
3226         if (!ares) {
3227                 return ldb_module_done(ac->req, NULL, NULL,
3228                                         LDB_ERR_OPERATIONS_ERROR);
3229         }
3230
3231         if (ares->type == LDB_REPLY_REFERRAL) {
3232                 return ldb_module_send_referral(ac->req, ares->referral);
3233         }
3234
3235         if (ares->error != LDB_SUCCESS) {
3236                 return ldb_module_done(ac->req, ares->controls,
3237                                         ares->response, ares->error);
3238         }
3239
3240         if (ares->type != LDB_REPLY_DONE) {
3241                 talloc_free(ares);
3242                 return ldb_module_done(ac->req, NULL, NULL,
3243                                         LDB_ERR_OPERATIONS_ERROR);
3244         }
3245
3246         talloc_free(ares);
3247
3248         return password_hash_mod_search_self(ac);
3249 }
3250
3251 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
3252 {
3253         struct ldb_context *ldb;
3254         struct ph_context *ac;
3255         int ret = LDB_SUCCESS;
3256
3257         ac = talloc_get_type(req->context, struct ph_context);
3258         ldb = ldb_module_get_ctx(ac->module);
3259
3260         if (!ares) {
3261                 ret = LDB_ERR_OPERATIONS_ERROR;
3262                 goto done;
3263         }
3264         if (ares->error != LDB_SUCCESS) {
3265                 return ldb_module_done(ac->req, ares->controls,
3266                                         ares->response, ares->error);
3267         }
3268
3269         /* we are interested only in the single reply (base search) */
3270         switch (ares->type) {
3271         case LDB_REPLY_ENTRY:
3272                 /* Make sure we are performing the password change action on a
3273                  * (for us) valid object. Those are instances of either "user"
3274                  * and/or "inetOrgPerson". Otherwise continue with the
3275                  * submodules. */
3276                 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
3277                         && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
3278                         talloc_free(ares);
3279
3280                         if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
3281                                 ldb_set_errstring(ldb,
3282                                                   "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
3283                                 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
3284                                 goto done;
3285                         }
3286
3287                         ret = ldb_next_request(ac->module, ac->req);
3288                         goto done;
3289                 }
3290
3291                 if (ac->search_res != NULL) {
3292                         talloc_free(ares);
3293
3294                         ldb_set_errstring(ldb, "Too many results");
3295                         ret = LDB_ERR_OPERATIONS_ERROR;
3296                         goto done;
3297                 }
3298
3299                 ac->search_res = talloc_steal(ac, ares);
3300                 ret = LDB_SUCCESS;
3301                 break;
3302
3303         case LDB_REPLY_REFERRAL:
3304                 /* ignore anything else for now */
3305                 talloc_free(ares);
3306                 ret = LDB_SUCCESS;
3307                 break;
3308
3309         case LDB_REPLY_DONE:
3310                 talloc_free(ares);
3311
3312                 /* get user domain data */
3313                 ret = build_domain_data_request(ac);
3314                 if (ret != LDB_SUCCESS) {
3315                         return ldb_module_done(ac->req, NULL, NULL, ret);
3316                 }
3317
3318                 ret = ldb_next_request(ac->module, ac->dom_req);
3319                 break;
3320         }
3321
3322 done:
3323         if (ret != LDB_SUCCESS) {
3324                 return ldb_module_done(ac->req, NULL, NULL, ret);
3325         }
3326
3327         return LDB_SUCCESS;
3328 }
3329
3330 static int password_hash_mod_search_self(struct ph_context *ac)
3331 {
3332         struct ldb_context *ldb;
3333         static const char * const attrs[] = { "objectClass",
3334                                               "userAccountControl",
3335                                               "msDS-User-Account-Control-Computed",
3336                                               "pwdLastSet",
3337                                               "sAMAccountName",
3338                                               "objectSid",
3339                                               "userPrincipalName",
3340                                               "supplementalCredentials",
3341                                               "lmPwdHistory",
3342                                               "ntPwdHistory",
3343                                               "dBCSPwd",
3344                                               "unicodePwd",
3345                                               "badPasswordTime",
3346                                               "badPwdCount",
3347                                               "lockoutTime",
3348                                               NULL };
3349         struct ldb_request *search_req;
3350         int ret;
3351
3352         ldb = ldb_module_get_ctx(ac->module);
3353
3354         ret = ldb_build_search_req(&search_req, ldb, ac,
3355                                    ac->req->op.mod.message->dn,
3356                                    LDB_SCOPE_BASE,
3357                                    "(objectclass=*)",
3358                                    attrs,
3359                                    NULL,
3360                                    ac, ph_mod_search_callback,
3361                                    ac->req);
3362         LDB_REQ_SET_LOCATION(search_req);
3363         if (ret != LDB_SUCCESS) {
3364                 return ret;
3365         }
3366
3367         return ldb_next_request(ac->module, search_req);
3368 }
3369
3370 static int password_hash_mod_do_mod(struct ph_context *ac)
3371 {
3372         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3373         struct loadparm_context *lp_ctx =
3374                                 talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3375                                                 struct loadparm_context);
3376         struct ldb_request *mod_req;
3377         struct ldb_message *msg;
3378         const struct ldb_message *orig_msg, *searched_msg;
3379         struct setup_password_fields_io io;
3380         int ret;
3381         NTSTATUS status;
3382
3383         /* use a new message structure so that we can modify it */
3384         msg = ldb_msg_new(ac);
3385         if (msg == NULL) {
3386                 return ldb_operr(ldb);
3387         }
3388
3389         /* modify dn */
3390         msg->dn = ac->req->op.mod.message->dn;
3391
3392         orig_msg = ac->req->op.mod.message;
3393         searched_msg = ac->search_res->message;
3394
3395         /* Prepare the internal data structure containing the passwords */
3396         ret = setup_io(ac, orig_msg, searched_msg, &io);
3397         if (ret != LDB_SUCCESS) {
3398                 return ret;
3399         }
3400         
3401         if (io.ac->pwd_reset) {
3402                 /* Get the old password from the database */
3403                 status = samdb_result_passwords_no_lockout(io.ac,
3404                                                            lp_ctx,
3405                                                            discard_const_p(struct ldb_message, searched_msg),
3406                                                            &io.o.lm_hash,
3407                                                            &io.o.nt_hash);
3408         } else {
3409                 /* Get the old password from the database */
3410                 status = samdb_result_passwords(io.ac,
3411                                                 lp_ctx,
3412                                                 discard_const_p(struct ldb_message, searched_msg),
3413                                                 &io.o.lm_hash, &io.o.nt_hash);
3414         }
3415
3416         if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
3417                 ldb_asprintf_errstring(ldb,
3418                                        "%08X: check_password: "
3419                                        "Password change not permitted, account locked out!",
3420                                        W_ERROR_V(WERR_ACCOUNT_LOCKED_OUT));
3421                 return LDB_ERR_CONSTRAINT_VIOLATION;
3422         }
3423
3424         if (!NT_STATUS_IS_OK(status)) {
3425                 /*
3426                  * This only happens if the database has gone weird,
3427                  * not if we are just missing the passwords
3428                  */
3429                 return ldb_operr(ldb);
3430         }
3431
3432         io.o.nt_history_len             = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
3433         io.o.lm_history_len             = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
3434         io.o.supplemental               = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
3435
3436         ret = setup_password_fields(&io);
3437         if (ret != LDB_SUCCESS) {
3438                 return ret;
3439         }
3440
3441         ret = check_password_restrictions(&io);
3442         if (ret != LDB_SUCCESS) {
3443                 return ret;
3444         }
3445
3446         /* make sure we replace all the old attributes */
3447         ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
3448         ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
3449         ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
3450         ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
3451         ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
3452         ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
3453
3454         if (io.g.nt_hash) {
3455                 ret = samdb_msg_add_hash(ldb, ac, msg,
3456                                          "unicodePwd", io.g.nt_hash);
3457                 if (ret != LDB_SUCCESS) {
3458                         return ret;
3459                 }
3460         }
3461         if (io.g.lm_hash) {
3462                 ret = samdb_msg_add_hash(ldb, ac, msg,
3463                                          "dBCSPwd", io.g.lm_hash);
3464                 if (ret != LDB_SUCCESS) {
3465                         return ret;
3466                 }
3467         }
3468         if (io.g.nt_history_len > 0) {
3469                 ret = samdb_msg_add_hashes(ldb, ac, msg,
3470                                            "ntPwdHistory",
3471                                            io.g.nt_history,
3472                                            io.g.nt_history_len);
3473                 if (ret != LDB_SUCCESS) {
3474                         return ret;
3475                 }
3476         }
3477         if (io.g.lm_history_len > 0) {
3478                 ret = samdb_msg_add_hashes(ldb, ac, msg,
3479                                            "lmPwdHistory",
3480                                            io.g.lm_history,
3481                                            io.g.lm_history_len);
3482                 if (ret != LDB_SUCCESS) {
3483                         return ret;
3484                 }
3485         }
3486         if (io.g.supplemental.length > 0) {
3487                 ret = ldb_msg_add_value(msg, "supplementalCredentials",
3488                                         &io.g.supplemental, NULL);
3489                 if (ret != LDB_SUCCESS) {
3490                         return ret;
3491                 }
3492         }
3493         ret = samdb_msg_add_uint64(ldb, ac, msg,
3494                                    "pwdLastSet",
3495                                    io.g.last_set);
3496         if (ret != LDB_SUCCESS) {
3497                 return ret;
3498         }
3499
3500         ret = ldb_build_mod_req(&mod_req, ldb, ac,
3501                                 msg,
3502                                 ac->req->controls,
3503                                 ac, ph_op_callback,
3504                                 ac->req);
3505         LDB_REQ_SET_LOCATION(mod_req);
3506         if (ret != LDB_SUCCESS) {
3507                 return ret;
3508         }
3509
3510         return ldb_next_request(ac->module, mod_req);
3511 }
3512
3513 static const struct ldb_module_ops ldb_password_hash_module_ops = {
3514         .name          = "password_hash",
3515         .add           = password_hash_add,
3516         .modify        = password_hash_modify
3517 };
3518
3519 int ldb_password_hash_module_init(const char *version)
3520 {
3521         LDB_MODULE_CHECK_VERSION(version);
3522         return ldb_register_module(&ldb_password_hash_module_ops);
3523 }