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