s4:dsdb/password_hash: allow pwdLastSet only changes
[samba.git] / source4 / dsdb / samdb / ldb_modules / password_hash.c
1 /* 
2    ldb database module
3
4    Copyright (C) Simo Sorce  2004-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Stefan Metzmacher 2007-2010
8    Copyright (C) Matthias Dieter Wallnöfer 2009-2010
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb password_hash module
28  *
29  *  Description: correctly handle AD password changes fields
30  *
31  *  Author: Andrew Bartlett
32  *  Author: Stefan Metzmacher
33  */
34
35 #include "includes.h"
36 #include "ldb_module.h"
37 #include "libcli/auth/libcli_auth.h"
38 #include "system/kerberos.h"
39 #include "auth/kerberos/kerberos.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/samdb/ldb_modules/util.h"
42 #include "dsdb/samdb/ldb_modules/password_modules.h"
43 #include "librpc/gen_ndr/ndr_drsblobs.h"
44 #include "../lib/crypto/crypto.h"
45 #include "param/param.h"
46 #include "lib/krb5_wrap/krb5_samba.h"
47
48 /* If we have decided there is a reason to work on this request, then
49  * setup all the password hash types correctly.
50  *
51  * If we haven't the hashes yet but the password given as plain-text (attributes
52  * 'unicodePwd', 'userPassword' and 'clearTextPassword') we have to check for
53  * the constraints. Once this is done, we calculate the password hashes.
54  *
55  * Notice: unlike the real AD which only supports the UTF16 special based
56  * 'unicodePwd' and the UTF8 based 'userPassword' plaintext attribute we
57  * understand also a UTF16 based 'clearTextPassword' one.
58  * The latter is also accessible through LDAP so it can also be set by external
59  * tools and scripts. But be aware that this isn't portable on non SAMBA 4 ADs!
60  *
61  * Also when the module receives only the password hashes (possible through
62  * specifying an internal LDB control - for security reasons) some checks are
63  * performed depending on the operation mode (see below) (e.g. if the password
64  * has been in use before if the password memory policy was activated).
65  *
66  * Attention: There is a difference between "modify" and "reset" operations
67  * (see MS-ADTS 3.1.1.3.1.5). If the client sends a "add" and "remove"
68  * operation for a password attribute we thread this as a "modify"; if it sends
69  * only a "replace" one we have an (administrative) reset.
70  *
71  * Finally, if the administrator has requested that a password history
72  * be maintained, then this should also be written out.
73  *
74  */
75
76 /* TODO: [consider always MS-ADTS 3.1.1.3.1.5]
77  * - Check for right connection encryption
78  */
79
80 /* Notice: Definition of "dsdb_control_password_change_status" moved into
81  * "samdb.h" */
82
83 struct ph_context {
84         struct ldb_module *module;
85         struct ldb_request *req;
86
87         struct ldb_request *dom_req;
88         struct ldb_reply *dom_res;
89
90         struct ldb_reply *search_res;
91
92         struct 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                 /* fall through */
1813         default:
1814                 GetTimeOfDay(&tv);
1815                 io->g.last_set = timeval_to_nttime(&tv);
1816                 break;
1817         }
1818
1819         if (io->ac->req->operation == LDB_ADD) {
1820                 /*
1821                  * We always need to store the value on add
1822                  * operations.
1823                  */
1824                 return LDB_SUCCESS;
1825         }
1826
1827         if (io->g.last_set == io->u.pwdLastSet) {
1828                 /*
1829                  * Just setting pwdLastSet to 0, is no-op if it's already 0.
1830                  */
1831                 io->ac->update_lastset = false;
1832         }
1833
1834         return LDB_SUCCESS;
1835 }
1836
1837 static int setup_given_passwords(struct setup_password_fields_io *io,
1838                                  struct setup_password_fields_given *g)
1839 {
1840         struct ldb_context *ldb;
1841         bool ok;
1842
1843         ldb = ldb_module_get_ctx(io->ac->module);
1844
1845         if (g->cleartext_utf8) {
1846                 struct ldb_val *cleartext_utf16_blob;
1847
1848                 cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
1849                 if (!cleartext_utf16_blob) {
1850                         return ldb_oom(ldb);
1851                 }
1852                 if (!convert_string_talloc(io->ac,
1853                                            CH_UTF8, CH_UTF16,
1854                                            g->cleartext_utf8->data,
1855                                            g->cleartext_utf8->length,
1856                                            (void *)&cleartext_utf16_blob->data,
1857                                            &cleartext_utf16_blob->length)) {
1858                         if (g->cleartext_utf8->length != 0) {
1859                                 talloc_free(cleartext_utf16_blob);
1860                                 ldb_asprintf_errstring(ldb,
1861                                                        "setup_password_fields: "
1862                                                        "failed to generate UTF16 password from cleartext UTF8 one for user '%s'!",
1863                                                        io->u.sAMAccountName);
1864                                 return LDB_ERR_CONSTRAINT_VIOLATION;
1865                         } else {
1866                                 /* passwords with length "0" are valid! */
1867                                 cleartext_utf16_blob->data = NULL;
1868                                 cleartext_utf16_blob->length = 0;
1869                         }
1870                 }
1871                 g->cleartext_utf16 = cleartext_utf16_blob;
1872         } else if (g->cleartext_utf16) {
1873                 struct ldb_val *cleartext_utf8_blob;
1874
1875                 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
1876                 if (!cleartext_utf8_blob) {
1877                         return ldb_oom(ldb);
1878                 }
1879                 if (!convert_string_talloc(io->ac,
1880                                            CH_UTF16MUNGED, CH_UTF8,
1881                                            g->cleartext_utf16->data,
1882                                            g->cleartext_utf16->length,
1883                                            (void *)&cleartext_utf8_blob->data,
1884                                            &cleartext_utf8_blob->length)) {
1885                         if (g->cleartext_utf16->length != 0) {
1886                                 /* We must bail out here, the input wasn't even
1887                                  * a multiple of 2 bytes */
1888                                 talloc_free(cleartext_utf8_blob);
1889                                 ldb_asprintf_errstring(ldb,
1890                                                        "setup_password_fields: "
1891                                                        "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)!",
1892                                                        io->u.sAMAccountName);
1893                                 return LDB_ERR_CONSTRAINT_VIOLATION;
1894                         } else {
1895                                 /* passwords with length "0" are valid! */
1896                                 cleartext_utf8_blob->data = NULL;
1897                                 cleartext_utf8_blob->length = 0;
1898                         }
1899                 }
1900                 g->cleartext_utf8 = cleartext_utf8_blob;
1901         }
1902
1903         if (g->cleartext_utf16) {
1904                 struct samr_Password *nt_hash;
1905
1906                 nt_hash = talloc(io->ac, struct samr_Password);
1907                 if (!nt_hash) {
1908                         return ldb_oom(ldb);
1909                 }
1910                 g->nt_hash = nt_hash;
1911
1912                 /* compute the new nt hash */
1913                 mdfour(nt_hash->hash,
1914                        g->cleartext_utf16->data,
1915                        g->cleartext_utf16->length);
1916         }
1917
1918         if (g->cleartext_utf8) {
1919                 struct samr_Password *lm_hash;
1920
1921                 lm_hash = talloc(io->ac, struct samr_Password);
1922                 if (!lm_hash) {
1923                         return ldb_oom(ldb);
1924                 }
1925
1926                 /* compute the new lm hash */
1927                 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
1928                 if (ok) {
1929                         g->lm_hash = lm_hash;
1930                 } else {
1931                         talloc_free(lm_hash);
1932                 }
1933         }
1934
1935         return LDB_SUCCESS;
1936 }
1937
1938 static int setup_password_fields(struct setup_password_fields_io *io)
1939 {
1940         struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1941         struct loadparm_context *lp_ctx =
1942                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1943                                          struct loadparm_context);
1944         int ret;
1945
1946         ret = setup_last_set_field(io);
1947         if (ret != LDB_SUCCESS) {
1948                 return ret;
1949         }
1950
1951         if (!io->ac->update_password) {
1952                 return LDB_SUCCESS;
1953         }
1954
1955         /* transform the old password (for password changes) */
1956         ret = setup_given_passwords(io, &io->og);
1957         if (ret != LDB_SUCCESS) {
1958                 return ret;
1959         }
1960
1961         /* transform the new password */
1962         ret = setup_given_passwords(io, &io->n);
1963         if (ret != LDB_SUCCESS) {
1964                 return ret;
1965         }
1966
1967         if (io->n.cleartext_utf8) {
1968                 ret = setup_kerberos_keys(io);
1969                 if (ret != LDB_SUCCESS) {
1970                         return ret;
1971                 }
1972         }
1973
1974         ret = setup_nt_fields(io);
1975         if (ret != LDB_SUCCESS) {
1976                 return ret;
1977         }
1978
1979         if (lpcfg_lanman_auth(lp_ctx)) {
1980                 ret = setup_lm_fields(io);
1981                 if (ret != LDB_SUCCESS) {
1982                         return ret;
1983                 }
1984         } else {
1985                 io->g.lm_hash = NULL;
1986                 io->g.lm_history_len = 0;
1987         }
1988
1989         ret = setup_supplemental_field(io);
1990         if (ret != LDB_SUCCESS) {
1991                 return ret;
1992         }
1993
1994         return LDB_SUCCESS;
1995 }
1996
1997 static int make_error_and_update_badPwdCount(struct setup_password_fields_io *io)
1998 {
1999         struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2000         struct ldb_message *mod_msg = NULL;
2001         NTSTATUS status;
2002         int ret;
2003
2004         status = dsdb_update_bad_pwd_count(io->ac, ldb,
2005                                            io->ac->search_res->message,
2006                                            io->ac->dom_res->message,
2007                                            &mod_msg);
2008         if (!NT_STATUS_IS_OK(status)) {
2009                 goto done;
2010         }
2011
2012         if (mod_msg == NULL) {
2013                 goto done;
2014         }
2015
2016         /*
2017          * OK, horrible semantics ahead.
2018          *
2019          * - We need to abort any existing transaction
2020          * - create a transaction arround the badPwdCount update
2021          * - re-open the transaction so the upper layer
2022          *   doesn't know what happened.
2023          *
2024          * This is needed because returning an error to the upper
2025          * layer will cancel the transaction and undo the badPwdCount
2026          * update.
2027          */
2028
2029         /*
2030          * Checking errors here is a bit pointless.
2031          * What can we do if we can't end the transaction?
2032          */
2033         ret = ldb_next_del_trans(io->ac->module);
2034         if (ret != LDB_SUCCESS) {
2035                 ldb_debug(ldb, LDB_DEBUG_FATAL,
2036                           "Failed to abort transaction prior to update of badPwdCount of %s: %s",
2037                           ldb_dn_get_linearized(io->ac->search_res->message->dn),
2038                           ldb_errstring(ldb));
2039                 /*
2040                  * just return the original error
2041                  */
2042                 goto done;
2043         }
2044
2045         /* Likewise, what should we do if we can't open a new transaction? */
2046         ret = ldb_next_start_trans(io->ac->module);
2047         if (ret != LDB_SUCCESS) {
2048                 ldb_debug(ldb, LDB_DEBUG_ERROR,
2049                           "Failed to open transaction to update badPwdCount of %s: %s",
2050                           ldb_dn_get_linearized(io->ac->search_res->message->dn),
2051                           ldb_errstring(ldb));
2052                 /*
2053                  * just return the original error
2054                  */
2055                 goto done;
2056         }
2057
2058         ret = dsdb_module_modify(io->ac->module, mod_msg,
2059                                  DSDB_FLAG_NEXT_MODULE,
2060                                  io->ac->req);
2061         if (ret != LDB_SUCCESS) {
2062                 ldb_debug(ldb, LDB_DEBUG_ERROR,
2063                           "Failed to update badPwdCount of %s: %s",
2064                           ldb_dn_get_linearized(io->ac->search_res->message->dn),
2065                           ldb_errstring(ldb));
2066                 /*
2067                  * We can only ignore this...
2068                  */
2069         }
2070
2071         ret = ldb_next_end_trans(io->ac->module);
2072         if (ret != LDB_SUCCESS) {
2073                 ldb_debug(ldb, LDB_DEBUG_ERROR,
2074                           "Failed to close transaction to update badPwdCount of %s: %s",
2075                           ldb_dn_get_linearized(io->ac->search_res->message->dn),
2076                           ldb_errstring(ldb));
2077                 /*
2078                  * We can only ignore this...
2079                  */
2080         }
2081
2082         ret = ldb_next_start_trans(io->ac->module);
2083         if (ret != LDB_SUCCESS) {
2084                 ldb_debug(ldb, LDB_DEBUG_ERROR,
2085                           "Failed to open transaction after update of badPwdCount of %s: %s",
2086                           ldb_dn_get_linearized(io->ac->search_res->message->dn),
2087                           ldb_errstring(ldb));
2088                 /*
2089                  * We can only ignore this...
2090                  */
2091         }
2092
2093 done:
2094         ret = LDB_ERR_CONSTRAINT_VIOLATION;
2095         ldb_asprintf_errstring(ldb,
2096                                "%08X: %s - check_password_restrictions: "
2097                                "The old password specified doesn't match!",
2098                                W_ERROR_V(WERR_INVALID_PASSWORD),
2099                                ldb_strerror(ret));
2100         return ret;
2101 }
2102
2103 static int check_password_restrictions(struct setup_password_fields_io *io)
2104 {
2105         struct ldb_context *ldb;
2106         int ret;
2107
2108         ldb = ldb_module_get_ctx(io->ac->module);
2109
2110         if (!io->ac->update_password) {
2111                 return LDB_SUCCESS;
2112         }
2113
2114         /* First check the old password is correct, for password changes */
2115         if (!io->ac->pwd_reset) {
2116                 bool nt_hash_checked = false;
2117
2118                 /* we need the old nt or lm hash given by the client */
2119                 if (!io->og.nt_hash && !io->og.lm_hash) {
2120                         ldb_asprintf_errstring(ldb,
2121                                 "check_password_restrictions: "
2122                                 "You need to provide the old password in order "
2123                                 "to change it!");
2124                         return LDB_ERR_UNWILLING_TO_PERFORM;
2125                 }
2126
2127                 /* The password modify through the NT hash is encouraged and
2128                    has no problems at all */
2129                 if (io->og.nt_hash) {
2130                         if (!io->o.nt_hash || memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
2131                                 return make_error_and_update_badPwdCount(io);
2132                         }
2133
2134                         nt_hash_checked = true;
2135                 }
2136
2137                 /* But it is also possible to change a password by the LM hash
2138                  * alone for compatibility reasons. This check is optional if
2139                  * the NT hash was already checked - otherwise it's mandatory.
2140                  * (as the SAMR operations request it). */
2141                 if (io->og.lm_hash) {
2142                         if ((!io->o.lm_hash && !nt_hash_checked)
2143                             || (io->o.lm_hash && memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0)) {
2144                                 return make_error_and_update_badPwdCount(io);
2145                         }
2146                 }
2147         }
2148
2149         if (io->u.restrictions == 0) {
2150                 /* FIXME: Is this right? */
2151                 return LDB_SUCCESS;
2152         }
2153
2154         /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
2155         if ((io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) &&
2156             !io->ac->pwd_reset)
2157         {
2158                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2159                 ldb_asprintf_errstring(ldb,
2160                         "%08X: %s - check_password_restrictions: "
2161                         "password is too young to change!",
2162                         W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2163                         ldb_strerror(ret));
2164                 return ret;
2165         }
2166
2167         /*
2168          * Fundamental password checks done by the call
2169          * "samdb_check_password".
2170          * It is also in use by "dcesrv_samr_ValidatePassword".
2171          */
2172         if (io->n.cleartext_utf8 != NULL) {
2173                 enum samr_ValidationStatus vstat;
2174                 vstat = samdb_check_password(io->n.cleartext_utf8,
2175                                              io->ac->status->domain_data.pwdProperties,
2176                                              io->ac->status->domain_data.minPwdLength);
2177                 switch (vstat) {
2178                 case SAMR_VALIDATION_STATUS_SUCCESS:
2179                                 /* perfect -> proceed! */
2180                         break;
2181
2182                 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
2183                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
2184                         ldb_asprintf_errstring(ldb,
2185                                 "%08X: %s - check_password_restrictions: "
2186                                 "the password is too short. It should be equal or longer than %u characters!",
2187                                 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2188                                 ldb_strerror(ret),
2189                                 io->ac->status->domain_data.minPwdLength);
2190                         io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
2191                         return ret;
2192
2193                 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
2194                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
2195                         ldb_asprintf_errstring(ldb,
2196                                 "%08X: %s - check_password_restrictions: "
2197                                 "the password does not meet the complexity criteria!",
2198                                 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2199                                 ldb_strerror(ret));
2200                         io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
2201                         return ret;
2202
2203                 default:
2204                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
2205                         ldb_asprintf_errstring(ldb,
2206                                 "%08X: %s - check_password_restrictions: "
2207                                 "the password doesn't fit by a certain reason!",
2208                                 W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2209                                 ldb_strerror(ret));
2210                         return ret;
2211                 }
2212         }
2213
2214         if (io->ac->pwd_reset) {
2215                 return LDB_SUCCESS;
2216         }
2217
2218         if (io->n.nt_hash) {
2219                 uint32_t i;
2220
2221                 /* checks the NT hash password history */
2222                 for (i = 0; i < io->o.nt_history_len; i++) {
2223                         ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
2224                         if (ret == 0) {
2225                                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2226                                 ldb_asprintf_errstring(ldb,
2227                                         "%08X: %s - check_password_restrictions: "
2228                                         "the password was already used (in history)!",
2229                                         W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2230                                         ldb_strerror(ret));
2231                                 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2232                                 return ret;
2233                         }
2234                 }
2235         }
2236
2237         if (io->n.lm_hash) {
2238                 uint32_t i;
2239
2240                 /* checks the LM hash password history */
2241                 for (i = 0; i < io->o.lm_history_len; i++) {
2242                         ret = memcmp(io->n.lm_hash, io->o.lm_history[i].hash, 16);
2243                         if (ret == 0) {
2244                                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2245                                 ldb_asprintf_errstring(ldb,
2246                                         "%08X: %s - check_password_restrictions: "
2247                                         "the password was already used (in history)!",
2248                                         W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2249                                         ldb_strerror(ret));
2250                                 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2251                                 return ret;
2252                         }
2253                 }
2254         }
2255
2256         /* are all password changes disallowed? */
2257         if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
2258                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2259                 ldb_asprintf_errstring(ldb,
2260                         "%08X: %s - check_password_restrictions: "
2261                         "password changes disabled!",
2262                         W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2263                         ldb_strerror(ret));
2264                 return ret;
2265         }
2266
2267         /* can this user change the password? */
2268         if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
2269                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
2270                 ldb_asprintf_errstring(ldb,
2271                         "%08X: %s - check_password_restrictions: "
2272                         "password can't be changed on this account!",
2273                         W_ERROR_V(WERR_PASSWORD_RESTRICTION),
2274                         ldb_strerror(ret));
2275                 return ret;
2276         }
2277
2278         return LDB_SUCCESS;
2279 }
2280
2281 static int update_final_msg(struct setup_password_fields_io *io)
2282 {
2283         struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2284         int ret;
2285         int el_flags = 0;
2286
2287         if (io->ac->req->operation == LDB_MODIFY) {
2288                 el_flags |= LDB_FLAG_MOD_REPLACE;
2289         }
2290
2291         /* make sure we replace all the old attributes */
2292         if (io->ac->update_password && el_flags != 0) {
2293                 ret = ldb_msg_add_empty(io->ac->update_msg,
2294                                         "unicodePwd",
2295                                         el_flags, NULL);
2296                 if (ret != LDB_SUCCESS) {
2297                         return ret;
2298                 }
2299                 ret = ldb_msg_add_empty(io->ac->update_msg,
2300                                         "dBCSPwd",
2301                                         el_flags, NULL);
2302                 if (ret != LDB_SUCCESS) {
2303                         return ret;
2304                 }
2305                 ret = ldb_msg_add_empty(io->ac->update_msg,
2306                                         "ntPwdHistory",
2307                                         el_flags, NULL);
2308                 if (ret != LDB_SUCCESS) {
2309                         return ret;
2310                 }
2311                 ret = ldb_msg_add_empty(io->ac->update_msg,
2312                                         "lmPwdHistory",
2313                                         el_flags, NULL);
2314                 if (ret != LDB_SUCCESS) {
2315                         return ret;
2316                 }
2317                 ret = ldb_msg_add_empty(io->ac->update_msg,
2318                                         "supplementalCredentials",
2319                                         el_flags, NULL);
2320                 if (ret != LDB_SUCCESS) {
2321                         return ret;
2322                 }
2323         }
2324         if (io->ac->update_lastset && el_flags != 0) {
2325                 ret = ldb_msg_add_empty(io->ac->update_msg,
2326                                         "pwdLastSet",
2327                                         el_flags, NULL);
2328                 if (ret != LDB_SUCCESS) {
2329                         return ret;
2330                 }
2331         }
2332
2333         if (io->g.nt_hash != NULL) {
2334                 ret = samdb_msg_add_hash(ldb, io->ac,
2335                                          io->ac->update_msg,
2336                                          "unicodePwd",
2337                                          io->g.nt_hash);
2338                 if (ret != LDB_SUCCESS) {
2339                         return ret;
2340                 }
2341         }
2342         if (io->g.lm_hash != NULL) {
2343                 ret = samdb_msg_add_hash(ldb, io->ac,
2344                                          io->ac->update_msg,
2345                                          "dBCSPwd",
2346                                          io->g.lm_hash);
2347                 if (ret != LDB_SUCCESS) {
2348                         return ret;
2349                 }
2350         }
2351         if (io->g.nt_history_len > 0) {
2352                 ret = samdb_msg_add_hashes(ldb, io->ac,
2353                                            io->ac->update_msg,
2354                                            "ntPwdHistory",
2355                                            io->g.nt_history,
2356                                            io->g.nt_history_len);
2357                 if (ret != LDB_SUCCESS) {
2358                         return ret;
2359                 }
2360         }
2361         if (io->g.lm_history_len > 0) {
2362                 ret = samdb_msg_add_hashes(ldb, io->ac,
2363                                            io->ac->update_msg,
2364                                            "lmPwdHistory",
2365                                            io->g.lm_history,
2366                                            io->g.lm_history_len);
2367                 if (ret != LDB_SUCCESS) {
2368                         return ret;
2369                 }
2370         }
2371         if (io->g.supplemental.length > 0) {
2372                 ret = ldb_msg_add_value(io->ac->update_msg,
2373                                         "supplementalCredentials",
2374                                         &io->g.supplemental, NULL);
2375                 if (ret != LDB_SUCCESS) {
2376                         return ret;
2377                 }
2378         }
2379         if (io->ac->update_lastset) {
2380                 ret = samdb_msg_add_uint64(ldb, io->ac,
2381                                            io->ac->update_msg,
2382                                            "pwdLastSet",
2383                                            io->g.last_set);
2384                 if (ret != LDB_SUCCESS) {
2385                         return ret;
2386                 }
2387         }
2388
2389         return LDB_SUCCESS;
2390 }
2391
2392 /*
2393  * This is intended for use by the "password_hash" module since there
2394  * password changes can be specified through one message element with the
2395  * new password (to set) and another one with the old password (to unset).
2396  *
2397  * The first which sets a password (new value) can have flags
2398  * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
2399  * for entries). The latter (old value) has always specified
2400  * LDB_FLAG_MOD_DELETE.
2401  *
2402  * Returns LDB_ERR_CONSTRAINT_VIOLATION and LDB_ERR_UNWILLING_TO_PERFORM if
2403  * matching message elements are malformed in respect to the set/change rules.
2404  * Otherwise it returns LDB_SUCCESS.
2405  */
2406 static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
2407                                         const char *name,
2408                                         enum ldb_request_type operation,
2409                                         const struct ldb_val **new_val,
2410                                         const struct ldb_val **old_val)
2411 {
2412         unsigned int i;
2413
2414         *new_val = NULL;
2415         *old_val = NULL;
2416
2417         if (msg == NULL) {
2418                 return LDB_SUCCESS;
2419         }
2420
2421         for (i = 0; i < msg->num_elements; i++) {
2422                 if (ldb_attr_cmp(msg->elements[i].name, name) != 0) {
2423                         continue;
2424                 }
2425
2426                 if ((operation == LDB_MODIFY) &&
2427                     (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE)) {
2428                         /* 0 values are allowed */
2429                         if (msg->elements[i].num_values == 1) {
2430                                 *old_val = &msg->elements[i].values[0];
2431                         } else if (msg->elements[i].num_values > 1) {
2432                                 return LDB_ERR_CONSTRAINT_VIOLATION;
2433                         }
2434                 } else if ((operation == LDB_MODIFY) &&
2435                            (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE)) {
2436                         if (msg->elements[i].num_values > 0) {
2437                                 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
2438                         } else {
2439                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2440                         }
2441                 } else {
2442                         /* Add operations and LDB_FLAG_MOD_ADD */
2443                         if (msg->elements[i].num_values > 0) {
2444                                 *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
2445                         } else {
2446                                 return LDB_ERR_CONSTRAINT_VIOLATION;
2447                         }
2448                 }
2449         }
2450
2451         return LDB_SUCCESS;
2452 }
2453
2454 static int setup_io(struct ph_context *ac, 
2455                     const struct ldb_message *client_msg,
2456                     const struct ldb_message *existing_msg,
2457                     struct setup_password_fields_io *io) 
2458
2459         const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
2460         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2461         struct loadparm_context *lp_ctx = talloc_get_type(
2462                 ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
2463         int ret;
2464         const struct ldb_message *info_msg = NULL;
2465
2466         ZERO_STRUCTP(io);
2467
2468         /* Some operations below require kerberos contexts */
2469
2470         if (existing_msg != NULL) {
2471                 /*
2472                  * This is a modify operation
2473                  */
2474                 info_msg = existing_msg;
2475         } else {
2476                 /*
2477                  * This is an add operation
2478                  */
2479                 info_msg = client_msg;
2480         }
2481
2482         if (smb_krb5_init_context(ac,
2483                                   (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
2484                                   &io->smb_krb5_context) != 0) {
2485                 return ldb_operr(ldb);
2486         }
2487
2488         io->ac                          = ac;
2489
2490         io->u.userAccountControl        = ldb_msg_find_attr_as_uint(info_msg,
2491                                                                     "userAccountControl", 0);
2492         if (info_msg == existing_msg) {
2493                 /*
2494                  * We only take pwdLastSet from the existing object
2495                  * otherwise we leave it as 0.
2496                  */
2497                 io->u.pwdLastSet = samdb_result_nttime(info_msg, "pwdLastSet", 0);
2498         }
2499         io->u.sAMAccountName            = ldb_msg_find_attr_as_string(info_msg,
2500                                                                       "sAMAccountName", NULL);
2501         io->u.user_principal_name       = ldb_msg_find_attr_as_string(info_msg,
2502                                                                       "userPrincipalName", NULL);
2503         io->u.is_computer               = ldb_msg_check_string_attribute(info_msg, "objectClass", "computer");
2504
2505         if (io->u.sAMAccountName == NULL) {
2506                 ldb_asprintf_errstring(ldb,
2507                                        "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
2508                                        ldb_dn_get_linearized(info_msg->dn));
2509
2510                 return LDB_ERR_CONSTRAINT_VIOLATION;
2511         }
2512
2513         if (io->u.userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
2514                 struct ldb_control *permit_trust = ldb_request_get_control(ac->req,
2515                                 DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID);
2516
2517                 if (permit_trust == NULL) {
2518                         ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2519                         ldb_asprintf_errstring(ldb,
2520                                 "%08X: %s - setup_io: changing the interdomain trust password "
2521                                 "on %s not allowed via LDAP. Use LSA or NETLOGON",
2522                                 W_ERROR_V(WERR_ACCESS_DENIED),
2523                                 ldb_strerror(ret),
2524                                 ldb_dn_get_linearized(info_msg->dn));
2525                         return ret;
2526                 }
2527         }
2528
2529         /* Only non-trust accounts have restrictions (possibly this test is the
2530          * wrong way around, but we like to be restrictive if possible */
2531         io->u.restrictions = !(io->u.userAccountControl
2532                 & (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
2533                         | UF_SERVER_TRUST_ACCOUNT));
2534
2535         if (ac->userPassword) {
2536                 ret = msg_find_old_and_new_pwd_val(client_msg, "userPassword",
2537                                                    ac->req->operation,
2538                                                    &io->n.cleartext_utf8,
2539                                                    &io->og.cleartext_utf8);
2540                 if (ret != LDB_SUCCESS) {
2541                         ldb_asprintf_errstring(ldb,
2542                                 "setup_io: "
2543                                 "it's only allowed to set the old password once!");
2544                         return ret;
2545                 }
2546         }
2547
2548         if (io->n.cleartext_utf8 != NULL) {
2549                 struct ldb_val *cleartext_utf8_blob;
2550                 char *p;
2551
2552                 cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
2553                 if (!cleartext_utf8_blob) {
2554                         return ldb_oom(ldb);
2555                 }
2556
2557                 *cleartext_utf8_blob = *io->n.cleartext_utf8;
2558
2559                 /* make sure we have a null terminated string */
2560                 p = talloc_strndup(cleartext_utf8_blob,
2561                                    (const char *)io->n.cleartext_utf8->data,
2562                                    io->n.cleartext_utf8->length);
2563                 if ((p == NULL) && (io->n.cleartext_utf8->length > 0)) {
2564                         return ldb_oom(ldb);
2565                 }
2566                 cleartext_utf8_blob->data = (uint8_t *)p;
2567
2568                 io->n.cleartext_utf8 = cleartext_utf8_blob;
2569         }
2570
2571         ret = msg_find_old_and_new_pwd_val(client_msg, "clearTextPassword",
2572                                            ac->req->operation,
2573                                            &io->n.cleartext_utf16,
2574                                            &io->og.cleartext_utf16);
2575         if (ret != LDB_SUCCESS) {
2576                 ldb_asprintf_errstring(ldb,
2577                         "setup_io: "
2578                         "it's only allowed to set the old password once!");
2579                 return ret;
2580         }
2581
2582         /* this rather strange looking piece of code is there to
2583            handle a ldap client setting a password remotely using the
2584            unicodePwd ldap field. The syntax is that the password is
2585            in UTF-16LE, with a " at either end. Unfortunately the
2586            unicodePwd field is also used to store the nt hashes
2587            internally in Samba, and is used in the nt hash format on
2588            the wire in DRS replication, so we have a single name for
2589            two distinct values. The code below leaves us with a small
2590            chance (less than 1 in 2^32) of a mixup, if someone manages
2591            to create a MD4 hash which starts and ends in 0x22 0x00, as
2592            that would then be treated as a UTF16 password rather than
2593            a nthash */
2594
2595         ret = msg_find_old_and_new_pwd_val(client_msg, "unicodePwd",
2596                                            ac->req->operation,
2597                                            &quoted_utf16,
2598                                            &old_quoted_utf16);
2599         if (ret != LDB_SUCCESS) {
2600                 ldb_asprintf_errstring(ldb,
2601                         "setup_io: "
2602                         "it's only allowed to set the old password once!");
2603                 return ret;
2604         }
2605
2606         /* Checks and converts the actual "unicodePwd" attribute */
2607         if (!ac->hash_values &&
2608             quoted_utf16 &&
2609             quoted_utf16->length >= 4 &&
2610             quoted_utf16->data[0] == '"' &&
2611             quoted_utf16->data[1] == 0 &&
2612             quoted_utf16->data[quoted_utf16->length-2] == '"' &&
2613             quoted_utf16->data[quoted_utf16->length-1] == 0) {
2614                 struct ldb_val *quoted_utf16_2;
2615
2616                 if (io->n.cleartext_utf16) {
2617                         /* refuse the change if someone wants to change with
2618                            with both UTF16 possibilities at the same time... */
2619                         ldb_asprintf_errstring(ldb,
2620                                 "setup_io: "
2621                                 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
2622                         return LDB_ERR_UNWILLING_TO_PERFORM;
2623                 }
2624
2625                 /*
2626                  * adapt the quoted UTF16 string to be a real
2627                  * cleartext one
2628                  */
2629                 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
2630                 if (quoted_utf16_2 == NULL) {
2631                         return ldb_oom(ldb);
2632                 }
2633
2634                 quoted_utf16_2->data = quoted_utf16->data + 2;
2635                 quoted_utf16_2->length = quoted_utf16->length-4;
2636                 io->n.cleartext_utf16 = quoted_utf16_2;
2637                 io->n.nt_hash = NULL;
2638
2639         } else if (quoted_utf16) {
2640                 /* We have only the hash available -> so no plaintext here */
2641                 if (!ac->hash_values) {
2642                         /* refuse the change if someone wants to change
2643                            the hash without control specified... */
2644                         ldb_asprintf_errstring(ldb,
2645                                 "setup_io: "
2646                                 "it's not allowed to set the NT hash password directly'");
2647                         /* this looks odd but this is what Windows does:
2648                            returns "UNWILLING_TO_PERFORM" on wrong
2649                            password sets and "CONSTRAINT_VIOLATION" on
2650                            wrong password changes. */
2651                         if (old_quoted_utf16 == NULL) {
2652                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2653                         }
2654
2655                         return LDB_ERR_CONSTRAINT_VIOLATION;
2656                 }
2657
2658                 io->n.nt_hash = talloc(io->ac, struct samr_Password);
2659                 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
2660                        MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
2661         }
2662
2663         /* Checks and converts the previous "unicodePwd" attribute */
2664         if (!ac->hash_values &&
2665             old_quoted_utf16 &&
2666             old_quoted_utf16->length >= 4 &&
2667             old_quoted_utf16->data[0] == '"' &&
2668             old_quoted_utf16->data[1] == 0 &&
2669             old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
2670             old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
2671                 struct ldb_val *old_quoted_utf16_2;
2672
2673                 if (io->og.cleartext_utf16) {
2674                         /* refuse the change if someone wants to change with
2675                            both UTF16 possibilities at the same time... */
2676                         ldb_asprintf_errstring(ldb,
2677                                 "setup_io: "
2678                                 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
2679                         return LDB_ERR_UNWILLING_TO_PERFORM;
2680                 }
2681
2682                 /*
2683                  * adapt the quoted UTF16 string to be a real
2684                  * cleartext one
2685                  */
2686                 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
2687                 if (old_quoted_utf16_2 == NULL) {
2688                         return ldb_oom(ldb);
2689                 }
2690
2691                 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
2692                 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
2693
2694                 io->og.cleartext_utf16 = old_quoted_utf16_2;
2695                 io->og.nt_hash = NULL;
2696         } else if (old_quoted_utf16) {
2697                 /* We have only the hash available -> so no plaintext here */
2698                 if (!ac->hash_values) {
2699                         /* refuse the change if someone wants to change
2700                            the hash without control specified... */
2701                         ldb_asprintf_errstring(ldb,
2702                                 "setup_io: "
2703                                 "it's not allowed to set the NT hash password directly'");
2704                         return LDB_ERR_UNWILLING_TO_PERFORM;
2705                 }
2706
2707                 io->og.nt_hash = talloc(io->ac, struct samr_Password);
2708                 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
2709                        MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
2710         }
2711
2712         /* Handles the "dBCSPwd" attribute (LM hash) */
2713         io->n.lm_hash = NULL; io->og.lm_hash = NULL;
2714         ret = msg_find_old_and_new_pwd_val(client_msg, "dBCSPwd",
2715                                            ac->req->operation,
2716                                            &lm_hash, &old_lm_hash);
2717         if (ret != LDB_SUCCESS) {
2718                 ldb_asprintf_errstring(ldb,
2719                         "setup_io: "
2720                         "it's only allowed to set the old password once!");
2721                 return ret;
2722         }
2723
2724         if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
2725                 /* refuse the change if someone wants to change the hash
2726                    without control specified... */
2727                 ldb_asprintf_errstring(ldb,
2728                         "setup_io: "
2729                         "it's not allowed to set the LM hash password directly'");
2730                 return LDB_ERR_UNWILLING_TO_PERFORM;
2731         }
2732
2733         if (lpcfg_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
2734                 io->n.lm_hash = talloc(io->ac, struct samr_Password);
2735                 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
2736                        sizeof(io->n.lm_hash->hash)));
2737         }
2738         if (lpcfg_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
2739                 io->og.lm_hash = talloc(io->ac, struct samr_Password);
2740                 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
2741                        sizeof(io->og.lm_hash->hash)));
2742         }
2743
2744         /*
2745          * Handles the password change control if it's specified. It has the
2746          * precedance and overrides already specified old password values of
2747          * change requests (but that shouldn't happen since the control is
2748          * fully internal and only used in conjunction with replace requests!).
2749          */
2750         if (ac->change != NULL) {
2751                 io->og.nt_hash = NULL;
2752                 if (ac->change->old_nt_pwd_hash != NULL) {
2753                         io->og.nt_hash = talloc_memdup(io->ac,
2754                                                        ac->change->old_nt_pwd_hash,
2755                                                        sizeof(struct samr_Password));
2756                 }
2757                 io->og.lm_hash = NULL;
2758                 if (lpcfg_lanman_auth(lp_ctx) && (ac->change->old_lm_pwd_hash != NULL)) {
2759                         io->og.lm_hash = talloc_memdup(io->ac,
2760                                                        ac->change->old_lm_pwd_hash,
2761                                                        sizeof(struct samr_Password));
2762                 }
2763         }
2764
2765         /* refuse the change if someone wants to change the clear-
2766            text and supply his own hashes at the same time... */
2767         if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
2768                         && (io->n.nt_hash || io->n.lm_hash)) {
2769                 ldb_asprintf_errstring(ldb,
2770                         "setup_io: "
2771                         "it's only allowed to set the password in form of cleartext attributes or as hashes");
2772                 return LDB_ERR_UNWILLING_TO_PERFORM;
2773         }
2774
2775         /* refuse the change if someone wants to change the password
2776            using both plaintext methods (UTF8 and UTF16) at the same time... */
2777         if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
2778                 ldb_asprintf_errstring(ldb,
2779                         "setup_io: "
2780                         "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
2781                 return LDB_ERR_UNWILLING_TO_PERFORM;
2782         }
2783
2784         /* refuse the change if someone tries to set/change the password by
2785          * the lanman hash alone and we've deactivated that mechanism. This
2786          * would end in an account without any password! */
2787         if (io->ac->update_password
2788             && (!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
2789             && (!io->n.nt_hash) && (!io->n.lm_hash)) {
2790                 ldb_asprintf_errstring(ldb,
2791                         "setup_io: "
2792                         "It's not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!");
2793                 /* on "userPassword" and "clearTextPassword" we've to return
2794                  * something different, since these are virtual attributes */
2795                 if ((ldb_msg_find_element(client_msg, "userPassword") != NULL) ||
2796                     (ldb_msg_find_element(client_msg, "clearTextPassword") != NULL)) {
2797                         return LDB_ERR_CONSTRAINT_VIOLATION;
2798                 }
2799                 return LDB_ERR_UNWILLING_TO_PERFORM;
2800         }
2801
2802         /* refuse the change if someone wants to compare against a plaintext
2803            or hash at the same time for a "password modify" operation... */
2804         if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
2805             && (io->og.nt_hash || io->og.lm_hash)) {
2806                 ldb_asprintf_errstring(ldb,
2807                         "setup_io: "
2808                         "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
2809                 return LDB_ERR_UNWILLING_TO_PERFORM;
2810         }
2811
2812         /* refuse the change if someone wants to compare against both
2813          * plaintexts at the same time for a "password modify" operation... */
2814         if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
2815                 ldb_asprintf_errstring(ldb,
2816                         "setup_io: "
2817                         "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
2818                 return LDB_ERR_UNWILLING_TO_PERFORM;
2819         }
2820
2821         /* Decides if we have a password modify or password reset operation */
2822         if (ac->req->operation == LDB_ADD) {
2823                 /* On "add" we have only "password reset" */
2824                 ac->pwd_reset = true;
2825         } else if (ac->req->operation == LDB_MODIFY) {
2826                 if (io->og.cleartext_utf8 || io->og.cleartext_utf16
2827                     || io->og.nt_hash || io->og.lm_hash) {
2828                         /* If we have an old password specified then for sure it
2829                          * is a user "password change" */
2830                         ac->pwd_reset = false;
2831                 } else {
2832                         /* Otherwise we have also here a "password reset" */
2833                         ac->pwd_reset = true;
2834                 }
2835         } else {
2836                 /* this shouldn't happen */
2837                 return ldb_operr(ldb);
2838         }
2839
2840         if (existing_msg != NULL) {
2841                 NTSTATUS status;
2842
2843                 if (ac->pwd_reset) {
2844                         /* Get the old password from the database */
2845                         status = samdb_result_passwords_no_lockout(ac,
2846                                                                    lp_ctx,
2847                                                                    existing_msg,
2848                                                                    &io->o.lm_hash,
2849                                                                    &io->o.nt_hash);
2850                 } else {
2851                         /* Get the old password from the database */
2852                         status = samdb_result_passwords(ac,
2853                                                         lp_ctx,
2854                                                         existing_msg,
2855                                                         &io->o.lm_hash,
2856                                                         &io->o.nt_hash);
2857                 }
2858
2859                 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
2860                         return dsdb_module_werror(ac->module,
2861                                                   LDB_ERR_CONSTRAINT_VIOLATION,
2862                                                   WERR_ACCOUNT_LOCKED_OUT,
2863                                                   "Password change not permitted,"
2864                                                   " account locked out!");
2865                 }
2866
2867                 if (!NT_STATUS_IS_OK(status)) {
2868                         /*
2869                          * This only happens if the database has gone weird,
2870                          * not if we are just missing the passwords
2871                          */
2872                         return ldb_operr(ldb);
2873                 }
2874
2875                 io->o.nt_history_len = samdb_result_hashes(ac, existing_msg,
2876                                                            "ntPwdHistory",
2877                                                            &io->o.nt_history);
2878                 io->o.lm_history_len = samdb_result_hashes(ac, existing_msg,
2879                                                            "lmPwdHistory",
2880                                                            &io->o.lm_history);
2881                 io->o.supplemental = ldb_msg_find_ldb_val(existing_msg,
2882                                                           "supplementalCredentials");
2883
2884                 if (io->o.supplemental != NULL) {
2885                         enum ndr_err_code ndr_err;
2886
2887                         ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
2888                                         &io->o.scb,
2889                                         (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
2890                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2891                                 status = ndr_map_error2ntstatus(ndr_err);
2892                                 ldb_asprintf_errstring(ldb,
2893                                                 "setup_io: failed to pull "
2894                                                 "old supplementalCredentialsBlob: %s",
2895                                                 nt_errstr(status));
2896                                 return LDB_ERR_OPERATIONS_ERROR;
2897                         }
2898                 }
2899         }
2900
2901         return LDB_SUCCESS;
2902 }
2903
2904 static struct ph_context *ph_init_context(struct ldb_module *module,
2905                                           struct ldb_request *req,
2906                                           bool userPassword,
2907                                           bool update_password)
2908 {
2909         struct ldb_context *ldb;
2910         struct ph_context *ac;
2911
2912         ldb = ldb_module_get_ctx(module);
2913
2914         ac = talloc_zero(req, struct ph_context);
2915         if (ac == NULL) {
2916                 ldb_set_errstring(ldb, "Out of Memory");
2917                 return NULL;
2918         }
2919
2920         ac->module = module;
2921         ac->req = req;
2922         ac->userPassword = userPassword;
2923         ac->update_password = update_password;
2924         ac->update_lastset = true;
2925
2926         return ac;
2927 }
2928
2929 static void ph_apply_controls(struct ph_context *ac)
2930 {
2931         struct ldb_control *ctrl;
2932
2933         ac->change_status = false;
2934         ctrl = ldb_request_get_control(ac->req,
2935                                        DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
2936         if (ctrl != NULL) {
2937                 ac->change_status = true;
2938
2939                 /* Mark the "change status" control as uncritical (done) */
2940                 ctrl->critical = false;
2941         }
2942
2943         ac->hash_values = false;
2944         ctrl = ldb_request_get_control(ac->req,
2945                                        DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
2946         if (ctrl != NULL) {
2947                 ac->hash_values = true;
2948
2949                 /* Mark the "hash values" control as uncritical (done) */
2950                 ctrl->critical = false;
2951         }
2952
2953         ctrl = ldb_request_get_control(ac->req,
2954                                        DSDB_CONTROL_PASSWORD_CHANGE_OID);
2955         if (ctrl != NULL) {
2956                 ac->change = (struct dsdb_control_password_change *) ctrl->data;
2957
2958                 /* Mark the "change" control as uncritical (done) */
2959                 ctrl->critical = false;
2960         }
2961
2962         ac->pwd_last_set_bypass = false;
2963         ctrl = ldb_request_get_control(ac->req,
2964                                 DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID);
2965         if (ctrl != NULL) {
2966                 ac->pwd_last_set_bypass = true;
2967
2968                 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
2969                 ctrl->critical = false;
2970         }
2971
2972         ac->pwd_last_set_default = false;
2973         ctrl = ldb_request_get_control(ac->req,
2974                                 DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID);
2975         if (ctrl != NULL) {
2976                 ac->pwd_last_set_default = true;
2977
2978                 /* Mark the "bypass pwdLastSet" control as uncritical (done) */
2979                 ctrl->critical = false;
2980         }
2981 }
2982
2983 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
2984 {
2985         struct ph_context *ac;
2986
2987         ac = talloc_get_type(req->context, struct ph_context);
2988
2989         if (!ares) {
2990                 return ldb_module_done(ac->req, NULL, NULL,
2991                                         LDB_ERR_OPERATIONS_ERROR);
2992         }
2993
2994         if (ares->type == LDB_REPLY_REFERRAL) {
2995                 return ldb_module_send_referral(ac->req, ares->referral);
2996         }
2997
2998         if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2999                 /* On success and trivial errors a status control is being
3000                  * added (used for example by the "samdb_set_password" call) */
3001                 ldb_reply_add_control(ares,
3002                                       DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
3003                                       false,
3004                                       ac->status);
3005         }
3006
3007         if (ares->error != LDB_SUCCESS) {
3008                 return ldb_module_done(ac->req, ares->controls,
3009                                         ares->response, ares->error);
3010         }
3011
3012         if (ares->type != LDB_REPLY_DONE) {
3013                 talloc_free(ares);
3014                 return ldb_module_done(ac->req, NULL, NULL,
3015                                         LDB_ERR_OPERATIONS_ERROR);
3016         }
3017
3018         return ldb_module_done(ac->req, ares->controls,
3019                                 ares->response, ares->error);
3020 }
3021
3022 static int password_hash_add_do_add(struct ph_context *ac);
3023 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
3024 static int password_hash_mod_search_self(struct ph_context *ac);
3025 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
3026 static int password_hash_mod_do_mod(struct ph_context *ac);
3027
3028 static int get_domain_data_callback(struct ldb_request *req,
3029                                     struct ldb_reply *ares)
3030 {
3031         struct ldb_context *ldb;
3032         struct ph_context *ac;
3033         struct loadparm_context *lp_ctx;
3034         int ret = LDB_SUCCESS;
3035
3036         ac = talloc_get_type(req->context, struct ph_context);
3037         ldb = ldb_module_get_ctx(ac->module);
3038
3039         if (!ares) {
3040                 ret = LDB_ERR_OPERATIONS_ERROR;
3041                 goto done;
3042         }
3043         if (ares->error != LDB_SUCCESS) {
3044                 return ldb_module_done(ac->req, ares->controls,
3045                                         ares->response, ares->error);
3046         }
3047
3048         switch (ares->type) {
3049         case LDB_REPLY_ENTRY:
3050                 if (ac->status != NULL) {
3051                         talloc_free(ares);
3052
3053                         ldb_set_errstring(ldb, "Too many results");
3054                         ret = LDB_ERR_OPERATIONS_ERROR;
3055                         goto done;
3056                 }
3057
3058                 /* Setup the "status" structure (used as control later) */
3059                 ac->status = talloc_zero(ac->req,
3060                                          struct dsdb_control_password_change_status);
3061                 if (ac->status == NULL) {
3062                         talloc_free(ares);
3063
3064                         ldb_oom(ldb);
3065                         ret = LDB_ERR_OPERATIONS_ERROR;
3066                         goto done;
3067                 }
3068
3069                 /* Setup the "domain data" structure */
3070                 ac->status->domain_data.pwdProperties =
3071                         ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
3072                 ac->status->domain_data.pwdHistoryLength =
3073                         ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
3074                 ac->status->domain_data.maxPwdAge =
3075                         ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
3076                 ac->status->domain_data.minPwdAge =
3077                         ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
3078                 ac->status->domain_data.minPwdLength =
3079                         ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
3080                 ac->status->domain_data.store_cleartext =
3081                         ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
3082
3083                 /* For a domain DN, this puts things in dotted notation */
3084                 /* For builtin domains, this will give details for the host,
3085                  * but that doesn't really matter, as it's just used for salt
3086                  * and kerberos principals, which don't exist here */
3087
3088                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3089                                          struct loadparm_context);
3090
3091                 ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
3092                 ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
3093                 ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
3094
3095                 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
3096
3097                 if (ac->dom_res != NULL) {
3098                         talloc_free(ares);
3099
3100                         ldb_set_errstring(ldb, "Too many results");
3101                         ret = LDB_ERR_OPERATIONS_ERROR;
3102                         goto done;
3103                 }
3104
3105                 ac->dom_res = talloc_steal(ac, ares);
3106                 ret = LDB_SUCCESS;
3107                 break;
3108
3109         case LDB_REPLY_REFERRAL:
3110                 /* ignore */
3111                 talloc_free(ares);
3112                 ret = LDB_SUCCESS;
3113                 break;
3114
3115         case LDB_REPLY_DONE:
3116                 talloc_free(ares);
3117                 /* call the next step */
3118                 switch (ac->req->operation) {
3119                 case LDB_ADD:
3120                         ret = password_hash_add_do_add(ac);
3121                         break;
3122
3123                 case LDB_MODIFY:
3124                         ret = password_hash_mod_do_mod(ac);
3125                         break;
3126
3127                 default:
3128                         ret = LDB_ERR_OPERATIONS_ERROR;
3129                         break;
3130                 }
3131                 break;
3132         }
3133
3134 done:
3135         if (ret != LDB_SUCCESS) {
3136                 struct ldb_reply *new_ares;
3137
3138                 new_ares = talloc_zero(ac->req, struct ldb_reply);
3139                 if (new_ares == NULL) {
3140                         ldb_oom(ldb);
3141                         return ldb_module_done(ac->req, NULL, NULL,
3142                                                LDB_ERR_OPERATIONS_ERROR);
3143                 }
3144
3145                 new_ares->error = ret;
3146                 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
3147                         /* On success and trivial errors a status control is being
3148                          * added (used for example by the "samdb_set_password" call) */
3149                         ldb_reply_add_control(new_ares,
3150                                               DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
3151                                               false,
3152                                               ac->status);
3153                 }
3154
3155                 return ldb_module_done(ac->req, new_ares->controls,
3156                                        new_ares->response, new_ares->error);
3157         }
3158
3159         return LDB_SUCCESS;
3160 }
3161
3162 static int build_domain_data_request(struct ph_context *ac)
3163 {
3164         /* attrs[] is returned from this function in
3165            ac->dom_req->op.search.attrs, so it must be static, as
3166            otherwise the compiler can put it on the stack */
3167         struct ldb_context *ldb;
3168         static const char * const attrs[] = { "pwdProperties",
3169                                               "pwdHistoryLength",
3170                                               "maxPwdAge",
3171                                               "minPwdAge",
3172                                               "minPwdLength",
3173                                               "lockoutThreshold",
3174                                               "lockOutObservationWindow",
3175                                               NULL };
3176         int ret;
3177
3178         ldb = ldb_module_get_ctx(ac->module);
3179
3180         ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
3181                                    ldb_get_default_basedn(ldb),
3182                                    LDB_SCOPE_BASE,
3183                                    NULL, attrs,
3184                                    NULL,
3185                                    ac, get_domain_data_callback,
3186                                    ac->req);
3187         LDB_REQ_SET_LOCATION(ac->dom_req);
3188         return ret;
3189 }
3190
3191 static int password_hash_needed(struct ldb_module *module,
3192                                 struct ldb_request *req,
3193                                 struct ph_context **_ac)
3194 {
3195         struct ldb_context *ldb = ldb_module_get_ctx(module);
3196         const char *operation = NULL;
3197         const struct ldb_message *msg = NULL;
3198         struct ph_context *ac = NULL;
3199         const char *passwordAttrs[] = {
3200                 "userPassword",
3201                 "clearTextPassword",
3202                 "unicodePwd",
3203                 "dBCSPwd",
3204                 NULL
3205         };
3206         const char **a = NULL;
3207         unsigned int attr_cnt = 0;
3208         struct ldb_control *bypass = NULL;
3209         bool userPassword = dsdb_user_password_support(module, req, req);
3210         bool update_password = false;
3211         bool processing_needed = false;
3212
3213         *_ac = NULL;
3214
3215         ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_needed\n");
3216
3217         switch (req->operation) {
3218         case LDB_ADD:
3219                 operation = "add";
3220                 msg = req->op.add.message;
3221                 break;
3222         case LDB_MODIFY:
3223                 operation = "modify";
3224                 msg = req->op.mod.message;
3225                 break;
3226         default:
3227                 return ldb_next_request(module, req);
3228         }
3229
3230         if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
3231                 return ldb_next_request(module, req);
3232         }
3233
3234         bypass = ldb_request_get_control(req,
3235                                          DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
3236         if (bypass != NULL) {
3237                 /* Mark the "bypass" control as uncritical (done) */
3238                 bypass->critical = false;
3239                 ldb_debug(ldb, LDB_DEBUG_TRACE,
3240                           "password_hash_needed(%s) (bypassing)\n",
3241                           operation);
3242                 return password_hash_bypass(module, req);
3243         }
3244
3245         /* nobody must touch password histories and 'supplementalCredentials' */
3246         if (ldb_msg_find_element(msg, "ntPwdHistory")) {
3247                 return LDB_ERR_UNWILLING_TO_PERFORM;
3248         }
3249         if (ldb_msg_find_element(msg, "lmPwdHistory")) {
3250                 return LDB_ERR_UNWILLING_TO_PERFORM;
3251         }
3252         if (ldb_msg_find_element(msg, "supplementalCredentials")) {
3253                 return LDB_ERR_UNWILLING_TO_PERFORM;
3254         }
3255
3256         /*
3257          * If no part of this touches the 'userPassword' OR 'clearTextPassword'
3258          * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
3259          * For password changes/set there should be a 'delete' or a 'modify'
3260          * on these attributes.
3261          */
3262         for (a = passwordAttrs; *a != NULL; a++) {
3263                 if ((!userPassword) && (ldb_attr_cmp(*a, "userPassword") == 0)) {
3264                         continue;
3265                 }
3266
3267                 if (ldb_msg_find_element(msg, *a) != NULL) {
3268                         /* MS-ADTS 3.1.1.3.1.5.2 */
3269                         if ((ldb_attr_cmp(*a, "userPassword") == 0) &&
3270                             (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
3271                                 return LDB_ERR_CONSTRAINT_VIOLATION;
3272                         }
3273
3274                         ++attr_cnt;
3275                 }
3276         }
3277
3278         if (attr_cnt > 0) {
3279                 update_password = true;
3280                 processing_needed = true;
3281         }
3282
3283         if (ldb_msg_find_element(msg, "pwdLastSet")) {
3284                 processing_needed = true;
3285         }
3286
3287         if (!processing_needed) {
3288                 return ldb_next_request(module, req);
3289         }
3290
3291         ac = ph_init_context(module, req, userPassword, update_password);
3292         if (!ac) {
3293                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3294                 return ldb_operr(ldb);
3295         }
3296         ph_apply_controls(ac);
3297
3298         /*
3299          * Make a copy in order to apply our modifications
3300          * to the final update
3301          */
3302         ac->update_msg = ldb_msg_copy_shallow(ac, msg);
3303         if (ac->update_msg == NULL) {
3304                 return ldb_oom(ldb);
3305         }
3306
3307         /*
3308          * Remove all password related attributes.
3309          */
3310         if (ac->userPassword) {
3311                 ldb_msg_remove_attr(ac->update_msg, "userPassword");
3312         }
3313         ldb_msg_remove_attr(ac->update_msg, "clearTextPassword");
3314         ldb_msg_remove_attr(ac->update_msg, "unicodePwd");
3315         ldb_msg_remove_attr(ac->update_msg, "ntPwdHistory");
3316         ldb_msg_remove_attr(ac->update_msg, "dBCSPwd");
3317         ldb_msg_remove_attr(ac->update_msg, "lmPwdHistory");
3318         ldb_msg_remove_attr(ac->update_msg, "supplementalCredentials");
3319         ldb_msg_remove_attr(ac->update_msg, "pwdLastSet");
3320
3321         *_ac = ac;
3322         return LDB_SUCCESS;
3323 }
3324
3325 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
3326 {
3327         struct ldb_context *ldb = ldb_module_get_ctx(module);
3328         struct ph_context *ac = NULL;
3329         int ret;
3330
3331         ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
3332
3333         ret = password_hash_needed(module, req, &ac);
3334         if (ret != LDB_SUCCESS) {
3335                 return ret;
3336         }
3337         if (ac == NULL) {
3338                 return ret;
3339         }
3340
3341         /* Make sure we are performing the password set action on a (for us)
3342          * valid object. Those are instances of either "user" and/or
3343          * "inetOrgPerson". Otherwise continue with the submodules. */
3344         if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
3345                 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
3346
3347                 TALLOC_FREE(ac);
3348
3349                 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
3350                         ldb_set_errstring(ldb,
3351                                           "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
3352                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
3353                 }
3354
3355                 return ldb_next_request(module, req);
3356         }
3357
3358         /* get user domain data */
3359         ret = build_domain_data_request(ac);
3360         if (ret != LDB_SUCCESS) {
3361                 return ret;
3362         }
3363
3364         return ldb_next_request(module, ac->dom_req);
3365 }
3366
3367 static int password_hash_add_do_add(struct ph_context *ac)
3368 {
3369         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3370         struct ldb_request *down_req;
3371         struct setup_password_fields_io io;
3372         int ret;
3373
3374         /* Prepare the internal data structure containing the passwords */
3375         ret = setup_io(ac, ac->req->op.add.message, NULL, &io);
3376         if (ret != LDB_SUCCESS) {
3377                 return ret;
3378         }
3379
3380         ret = setup_password_fields(&io);
3381         if (ret != LDB_SUCCESS) {
3382                 return ret;
3383         }
3384
3385         ret = check_password_restrictions(&io);
3386         if (ret != LDB_SUCCESS) {
3387                 return ret;
3388         }
3389
3390         ret = update_final_msg(&io);
3391         if (ret != LDB_SUCCESS) {
3392                 return ret;
3393         }
3394
3395         ret = ldb_build_add_req(&down_req, ldb, ac,
3396                                 ac->update_msg,
3397                                 ac->req->controls,
3398                                 ac, ph_op_callback,
3399                                 ac->req);
3400         LDB_REQ_SET_LOCATION(down_req);
3401         if (ret != LDB_SUCCESS) {
3402                 return ret;
3403         }
3404
3405         return ldb_next_request(ac->module, down_req);
3406 }
3407
3408 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
3409 {
3410         struct ldb_context *ldb = ldb_module_get_ctx(module);
3411         struct ph_context *ac = NULL;
3412         const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
3413                 "unicodePwd", "dBCSPwd", NULL }, **l;
3414         unsigned int del_attr_cnt, add_attr_cnt, rep_attr_cnt;
3415         struct ldb_message_element *passwordAttr;
3416         struct ldb_message *msg;
3417         struct ldb_request *down_req;
3418         int ret;
3419         unsigned int i = 0;
3420
3421         ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
3422
3423         ret = password_hash_needed(module, req, &ac);
3424         if (ret != LDB_SUCCESS) {
3425                 return ret;
3426         }
3427         if (ac == NULL) {
3428                 return ret;
3429         }
3430
3431         /* use a new message structure so that we can modify it */
3432         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3433         if (msg == NULL) {
3434                 return ldb_oom(ldb);
3435         }
3436
3437         /* - check for single-valued password attributes
3438          *   (if not return "CONSTRAINT_VIOLATION")
3439          * - check that for a password change operation one add and one delete
3440          *   operation exists
3441          *   (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
3442          * - check that a password change and a password set operation cannot
3443          *   be mixed
3444          *   (if not return "UNWILLING_TO_PERFORM")
3445          * - remove all password attributes modifications from the first change
3446          *   operation (anything without the passwords) - we will make the real
3447          *   modification later */
3448         del_attr_cnt = 0;
3449         add_attr_cnt = 0;
3450         rep_attr_cnt = 0;
3451         for (l = passwordAttrs; *l != NULL; l++) {
3452                 if ((!ac->userPassword) &&
3453                     (ldb_attr_cmp(*l, "userPassword") == 0)) {
3454                         continue;
3455                 }
3456
3457                 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
3458                         if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE) {
3459                                 ++del_attr_cnt;
3460                         }
3461                         if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD) {
3462                                 ++add_attr_cnt;
3463                         }
3464                         if (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_REPLACE) {
3465                                 ++rep_attr_cnt;
3466                         }
3467                         if ((passwordAttr->num_values != 1) &&
3468                             (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_ADD)) {
3469                                 talloc_free(ac);
3470                                 ldb_asprintf_errstring(ldb,
3471                                                        "'%s' attribute must have exactly one value on add operations!",
3472                                                        *l);
3473                                 return LDB_ERR_CONSTRAINT_VIOLATION;
3474                         }
3475                         if ((passwordAttr->num_values > 1) &&
3476                             (LDB_FLAG_MOD_TYPE(passwordAttr->flags) == LDB_FLAG_MOD_DELETE)) {
3477                                 talloc_free(ac);
3478                                 ldb_asprintf_errstring(ldb,
3479                                                        "'%s' attribute must have zero or one value(s) on delete operations!",
3480                                                        *l);
3481                                 return LDB_ERR_CONSTRAINT_VIOLATION;
3482                         }
3483                         ldb_msg_remove_element(msg, passwordAttr);
3484                 }
3485         }
3486         if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
3487                 talloc_free(ac);
3488                 ldb_set_errstring(ldb,
3489                                   "Only the add action for a password change specified!");
3490                 return LDB_ERR_UNWILLING_TO_PERFORM;
3491         }
3492         if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
3493                 talloc_free(ac);
3494                 ldb_set_errstring(ldb,
3495                                   "Only one delete and one add action for a password change allowed!");
3496                 return LDB_ERR_UNWILLING_TO_PERFORM;
3497         }
3498         if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
3499                 talloc_free(ac);
3500                 ldb_set_errstring(ldb,
3501                                   "Either a password change or a password set operation is allowed!");
3502                 return LDB_ERR_UNWILLING_TO_PERFORM;
3503         }
3504
3505         ldb_msg_remove_attr(msg, "pwdLastSet");
3506
3507         /* if there was nothing else to be modified skip to next step */
3508         if (msg->num_elements == 0) {
3509                 return password_hash_mod_search_self(ac);
3510         }
3511
3512         /*
3513          * Now we apply all changes remaining in msg
3514          * and remove them from our final update_msg
3515          */
3516
3517         for (i = 0; i < msg->num_elements; i++) {
3518                 ldb_msg_remove_attr(ac->update_msg,
3519                                     msg->elements[i].name);
3520         }
3521
3522         ret = ldb_build_mod_req(&down_req, ldb, ac,
3523                                 msg,
3524                                 req->controls,
3525                                 ac, ph_modify_callback,
3526                                 req);
3527         LDB_REQ_SET_LOCATION(down_req);
3528         if (ret != LDB_SUCCESS) {
3529                 return ret;
3530         }
3531
3532         return ldb_next_request(module, down_req);
3533 }
3534
3535 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3536 {
3537         struct ph_context *ac;
3538
3539         ac = talloc_get_type(req->context, struct ph_context);
3540
3541         if (!ares) {
3542                 return ldb_module_done(ac->req, NULL, NULL,
3543                                         LDB_ERR_OPERATIONS_ERROR);
3544         }
3545
3546         if (ares->type == LDB_REPLY_REFERRAL) {
3547                 return ldb_module_send_referral(ac->req, ares->referral);
3548         }
3549
3550         if (ares->error != LDB_SUCCESS) {
3551                 return ldb_module_done(ac->req, ares->controls,
3552                                         ares->response, ares->error);
3553         }
3554
3555         if (ares->type != LDB_REPLY_DONE) {
3556                 talloc_free(ares);
3557                 return ldb_module_done(ac->req, NULL, NULL,
3558                                         LDB_ERR_OPERATIONS_ERROR);
3559         }
3560
3561         talloc_free(ares);
3562
3563         return password_hash_mod_search_self(ac);
3564 }
3565
3566 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
3567 {
3568         struct ldb_context *ldb;
3569         struct ph_context *ac;
3570         int ret = LDB_SUCCESS;
3571
3572         ac = talloc_get_type(req->context, struct ph_context);
3573         ldb = ldb_module_get_ctx(ac->module);
3574
3575         if (!ares) {
3576                 ret = LDB_ERR_OPERATIONS_ERROR;
3577                 goto done;
3578         }
3579         if (ares->error != LDB_SUCCESS) {
3580                 return ldb_module_done(ac->req, ares->controls,
3581                                         ares->response, ares->error);
3582         }
3583
3584         /* we are interested only in the single reply (base search) */
3585         switch (ares->type) {
3586         case LDB_REPLY_ENTRY:
3587                 /* Make sure we are performing the password change action on a
3588                  * (for us) valid object. Those are instances of either "user"
3589                  * and/or "inetOrgPerson". Otherwise continue with the
3590                  * submodules. */
3591                 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
3592                         && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
3593                         talloc_free(ares);
3594
3595                         if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
3596                                 ldb_set_errstring(ldb,
3597                                                   "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
3598                                 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
3599                                 goto done;
3600                         }
3601
3602                         ret = ldb_next_request(ac->module, ac->req);
3603                         goto done;
3604                 }
3605
3606                 if (ac->search_res != NULL) {
3607                         talloc_free(ares);
3608
3609                         ldb_set_errstring(ldb, "Too many results");
3610                         ret = LDB_ERR_OPERATIONS_ERROR;
3611                         goto done;
3612                 }
3613
3614                 ac->search_res = talloc_steal(ac, ares);
3615                 ret = LDB_SUCCESS;
3616                 break;
3617
3618         case LDB_REPLY_REFERRAL:
3619                 /* ignore anything else for now */
3620                 talloc_free(ares);
3621                 ret = LDB_SUCCESS;
3622                 break;
3623
3624         case LDB_REPLY_DONE:
3625                 talloc_free(ares);
3626
3627                 /* get user domain data */
3628                 ret = build_domain_data_request(ac);
3629                 if (ret != LDB_SUCCESS) {
3630                         return ldb_module_done(ac->req, NULL, NULL, ret);
3631                 }
3632
3633                 ret = ldb_next_request(ac->module, ac->dom_req);
3634                 break;
3635         }
3636
3637 done:
3638         if (ret != LDB_SUCCESS) {
3639                 return ldb_module_done(ac->req, NULL, NULL, ret);
3640         }
3641
3642         return LDB_SUCCESS;
3643 }
3644
3645 static int password_hash_mod_search_self(struct ph_context *ac)
3646 {
3647         struct ldb_context *ldb;
3648         static const char * const attrs[] = { "objectClass",
3649                                               "userAccountControl",
3650                                               "msDS-User-Account-Control-Computed",
3651                                               "pwdLastSet",
3652                                               "sAMAccountName",
3653                                               "objectSid",
3654                                               "userPrincipalName",
3655                                               "supplementalCredentials",
3656                                               "lmPwdHistory",
3657                                               "ntPwdHistory",
3658                                               "dBCSPwd",
3659                                               "unicodePwd",
3660                                               "badPasswordTime",
3661                                               "badPwdCount",
3662                                               "lockoutTime",
3663                                               NULL };
3664         struct ldb_request *search_req;
3665         int ret;
3666
3667         ldb = ldb_module_get_ctx(ac->module);
3668
3669         ret = ldb_build_search_req(&search_req, ldb, ac,
3670                                    ac->req->op.mod.message->dn,
3671                                    LDB_SCOPE_BASE,
3672                                    "(objectclass=*)",
3673                                    attrs,
3674                                    NULL,
3675                                    ac, ph_mod_search_callback,
3676                                    ac->req);
3677         LDB_REQ_SET_LOCATION(search_req);
3678         if (ret != LDB_SUCCESS) {
3679                 return ret;
3680         }
3681
3682         return ldb_next_request(ac->module, search_req);
3683 }
3684
3685 static int password_hash_mod_do_mod(struct ph_context *ac)
3686 {
3687         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3688         struct ldb_request *mod_req;
3689         struct setup_password_fields_io io;
3690         int ret;
3691
3692         /* Prepare the internal data structure containing the passwords */
3693         ret = setup_io(ac, ac->req->op.mod.message,
3694                        ac->search_res->message, &io);
3695         if (ret != LDB_SUCCESS) {
3696                 return ret;
3697         }
3698
3699         ret = setup_password_fields(&io);
3700         if (ret != LDB_SUCCESS) {
3701                 return ret;
3702         }
3703
3704         ret = check_password_restrictions(&io);
3705         if (ret != LDB_SUCCESS) {
3706                 return ret;
3707         }
3708
3709         ret = update_final_msg(&io);
3710         if (ret != LDB_SUCCESS) {
3711                 return ret;
3712         }
3713
3714         ret = ldb_build_mod_req(&mod_req, ldb, ac,
3715                                 ac->update_msg,
3716                                 ac->req->controls,
3717                                 ac, ph_op_callback,
3718                                 ac->req);
3719         LDB_REQ_SET_LOCATION(mod_req);
3720         if (ret != LDB_SUCCESS) {
3721                 return ret;
3722         }
3723
3724         return ldb_next_request(ac->module, mod_req);
3725 }
3726
3727 static const struct ldb_module_ops ldb_password_hash_module_ops = {
3728         .name          = "password_hash",
3729         .add           = password_hash_add,
3730         .modify        = password_hash_modify
3731 };
3732
3733 int ldb_password_hash_module_init(const char *version)
3734 {
3735         LDB_MODULE_CHECK_VERSION(version);
3736         return ldb_register_module(&ldb_password_hash_module_ops);
3737 }