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