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