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