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