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