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