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