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