s4:dsdb/password_hash: fix some c++ compiler warnings
[samba.git] / source4 / dsdb / samdb / ldb_modules / password_hash.c
1 /* 
2    ldb database module
3
4    Copyright (C) Simo Sorce  2004-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Stefan Metzmacher 2007-2010
8    Copyright (C) Matthias Dieter Wallnöfer 2009-2010
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb password_hash module
28  *
29  *  Description: correctly handle AD password changes fields
30  *
31  *  Author: Andrew Bartlett
32  *  Author: Stefan Metzmacher
33  */
34
35 #include "includes.h"
36 #include "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 LM 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(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                 struct samr_Password *lm_hash;
1387
1388                 lm_hash = talloc(io->ac, struct samr_Password);
1389                 if (!lm_hash) {
1390                         ldb_oom(ldb);
1391                         return LDB_ERR_OPERATIONS_ERROR;
1392                 }
1393
1394                 /* compute the new lm hash */
1395                 ok = E_deshash((char *)g->cleartext_utf8->data, lm_hash->hash);
1396                 if (ok) {
1397                         g->lm_hash = lm_hash;
1398                 } else {
1399                         talloc_free(lm_hash);
1400                 }
1401         }
1402
1403         return LDB_SUCCESS;
1404 }
1405
1406 static int setup_password_fields(struct setup_password_fields_io *io)
1407 {
1408         struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1409         struct loadparm_context *lp_ctx =
1410                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1411                                          struct loadparm_context);
1412         int ret;
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         if (lp_lanman_auth(lp_ctx)) {
1439                 ret = setup_lm_fields(io);
1440                 if (ret != LDB_SUCCESS) {
1441                         return ret;
1442                 }
1443         } else {
1444                 io->g.lm_hash = NULL;
1445                 io->g.lm_history_len = 0;
1446         }
1447
1448         ret = setup_supplemental_field(io);
1449         if (ret != LDB_SUCCESS) {
1450                 return ret;
1451         }
1452
1453         ret = setup_last_set_field(io);
1454         if (ret != LDB_SUCCESS) {
1455                 return ret;
1456         }
1457
1458         return LDB_SUCCESS;
1459 }
1460
1461 static int check_password_restrictions(struct setup_password_fields_io *io)
1462 {
1463         struct ldb_context *ldb;
1464         int ret;
1465         enum samr_ValidationStatus stat;
1466
1467         ldb = ldb_module_get_ctx(io->ac->module);
1468
1469         /* First check the old password is correct, for password changes */
1470         if (!io->ac->pwd_reset && !io->ac->change_old_pw_checked) {
1471                 /* we need to old nt or lm hash given by the client */
1472                 if (!io->og.nt_hash && !io->og.lm_hash) {
1473                         ldb_asprintf_errstring(ldb,
1474                                 "check_password_restrictions: "
1475                                 "You need to provide the old password "
1476                                 "in order to change your password!");
1477                         return LDB_ERR_UNWILLING_TO_PERFORM;
1478                 }
1479
1480                 if (io->og.nt_hash) {
1481                         if (!io->o.nt_hash) {
1482                                 ldb_asprintf_errstring(ldb,
1483                                         "check_password_restrictions: "
1484                                         "There's no old nt_hash, which is needed "
1485                                         "in order to change your password!");
1486                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1487                         }
1488
1489                         /* The password modify through the NT hash is encouraged
1490                            and has no problems at all */
1491                         if (memcmp(io->og.nt_hash->hash, io->o.nt_hash->hash, 16) != 0) {
1492                                 ldb_asprintf_errstring(ldb,
1493                                         "check_password_restrictions: "
1494                                         "The old password specified doesn't match!");
1495                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1496                         }
1497                 } else if (io->og.lm_hash) {
1498                         if (!io->o.lm_hash) {
1499                                 ldb_asprintf_errstring(ldb,
1500                                         "check_password_restrictions: "
1501                                         "There's no old lm_hash, which is needed "
1502                                         "in order to change your password!");
1503                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1504                         }
1505
1506                         if (memcmp(io->og.lm_hash->hash, io->o.lm_hash->hash, 16) != 0) {
1507                                 ldb_asprintf_errstring(ldb,
1508                                         "check_password_restrictions: "
1509                                         "The old password specified doesn't match!");
1510                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1511                         }
1512                 }
1513         }
1514
1515         if (io->u.restrictions == 0) {
1516                 /* FIXME: Is this right? */
1517                 return LDB_SUCCESS;
1518         }
1519
1520         /*
1521          * Fundamental password checks done by the call
1522          * "samdb_check_password".
1523          * It is also in use by "dcesrv_samr_ValidatePassword".
1524          */
1525         if (io->n.cleartext_utf8 != NULL) {
1526                 stat = samdb_check_password(io->n.cleartext_utf8,
1527                                             io->ac->status->domain_data.pwdProperties,
1528                                             io->ac->status->domain_data.minPwdLength);
1529                 switch (stat) {
1530                 case SAMR_VALIDATION_STATUS_SUCCESS:
1531                                 /* perfect -> proceed! */
1532                         break;
1533
1534                 case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
1535                         ldb_asprintf_errstring(ldb,
1536                                 "check_password_restrictions: "
1537                                 "the password is too short. It should be equal or longer than %i characters!",
1538                                 io->ac->status->domain_data.minPwdLength);
1539
1540                         io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
1541                         return LDB_ERR_CONSTRAINT_VIOLATION;
1542
1543                 case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
1544                         ldb_asprintf_errstring(ldb,
1545                                 "check_password_restrictions: "
1546                                 "the password does not meet the complexity criterias!");
1547                         io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
1548
1549                         return LDB_ERR_CONSTRAINT_VIOLATION;
1550
1551                 default:
1552                         ldb_asprintf_errstring(ldb,
1553                                 "check_password_restrictions: "
1554                                 "the password doesn't fit by a certain reason!");
1555
1556                         return LDB_ERR_CONSTRAINT_VIOLATION;
1557                 }
1558         }
1559
1560         if (io->ac->pwd_reset) {
1561                 return LDB_SUCCESS;
1562         }
1563
1564         if (io->n.nt_hash) {
1565                 uint32_t i;
1566
1567                 /* checks the NT hash password history */
1568                 for (i = 0; i < io->o.nt_history_len; i++) {
1569                         ret = memcmp(io->n.nt_hash, io->o.nt_history[i].hash, 16);
1570                         if (ret == 0) {
1571                                 ldb_asprintf_errstring(ldb,
1572                                         "check_password_restrictions: "
1573                                         "the password was already used (in history)!");
1574
1575                                 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1576
1577                                 return LDB_ERR_CONSTRAINT_VIOLATION;
1578                         }
1579                 }
1580         }
1581
1582         if (io->n.lm_hash) {
1583                 uint32_t i;
1584
1585                 /* checks the LM hash password history */
1586                 for (i = 0; i < io->o.lm_history_len; i++) {
1587                         ret = memcmp(io->n.nt_hash, io->o.lm_history[i].hash, 16);
1588                         if (ret == 0) {
1589                                 ldb_asprintf_errstring(ldb,
1590                                         "check_password_restrictions: "
1591                                         "the password was already used (in history)!");
1592
1593                                 io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1594
1595                                 return LDB_ERR_CONSTRAINT_VIOLATION;
1596                         }
1597                 }
1598         }
1599
1600         /* are all password changes disallowed? */
1601         if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1602                 ldb_asprintf_errstring(ldb,
1603                         "check_password_restrictions: "
1604                         "password changes disabled!");
1605                 return LDB_ERR_CONSTRAINT_VIOLATION;
1606         }
1607
1608         /* can this user change the password? */
1609         if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
1610                 ldb_asprintf_errstring(ldb,
1611                         "check_password_restrictions: "
1612                         "password can't be changed on this account!");
1613                 return LDB_ERR_CONSTRAINT_VIOLATION;
1614         }
1615
1616         /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
1617         if (io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) {
1618                 ldb_asprintf_errstring(ldb,
1619                         "check_password_restrictions: "
1620                         "password is too young to change!");
1621                 return LDB_ERR_CONSTRAINT_VIOLATION;
1622         }
1623
1624         return LDB_SUCCESS;
1625 }
1626
1627 static int setup_io(struct ph_context *ac, 
1628                     const struct ldb_message *orig_msg,
1629                     const struct ldb_message *searched_msg, 
1630                     struct setup_password_fields_io *io) 
1631
1632         const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
1633         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1634         struct loadparm_context *lp_ctx =
1635                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1636                                          struct loadparm_context);
1637         int ret;
1638
1639         ZERO_STRUCTP(io);
1640
1641         /* Some operations below require kerberos contexts */
1642
1643         if (smb_krb5_init_context(ac,
1644                                   ldb_get_event_context(ldb),
1645                                   (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
1646                                   &io->smb_krb5_context) != 0) {
1647                 return LDB_ERR_OPERATIONS_ERROR;
1648         }
1649
1650         io->ac                          = ac;
1651
1652         io->u.userAccountControl        = samdb_result_uint(searched_msg, "userAccountControl", 0);
1653         io->u.pwdLastSet                = samdb_result_nttime(searched_msg, "pwdLastSet", 0);
1654         io->u.sAMAccountName            = samdb_result_string(searched_msg, "sAMAccountName", NULL);
1655         io->u.user_principal_name       = samdb_result_string(searched_msg, "userPrincipalName", NULL);
1656         io->u.is_computer               = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
1657
1658         if (io->u.sAMAccountName == NULL) {
1659                 ldb_asprintf_errstring(ldb,
1660                                        "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
1661                                        ldb_dn_get_linearized(searched_msg->dn));
1662
1663                 return LDB_ERR_CONSTRAINT_VIOLATION;
1664         }
1665
1666         /* Only non-trust accounts have restrictions (possibly this test is the
1667          * wrong way around, but we like to be restrictive if possible */
1668         io->u.restrictions = !(io->u.userAccountControl
1669                 & (UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT
1670                         | UF_SERVER_TRUST_ACCOUNT));
1671
1672         if ((io->u.userAccountControl & UF_PASSWD_NOTREQD) != 0) {
1673                 /* see [MS-ADTS] 2.2.15 */
1674                 io->u.restrictions = 0;
1675         }
1676
1677         ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "userPassword",
1678                 &io->n.cleartext_utf8, &io->og.cleartext_utf8);
1679         if (ret != LDB_SUCCESS) {
1680                 ldb_asprintf_errstring(ldb,
1681                         "setup_io: "
1682                         "it's only allowed to set the old password once!");
1683                 return ret;
1684         }
1685
1686         ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "clearTextPassword",
1687                 &io->n.cleartext_utf16, &io->og.cleartext_utf16);
1688         if (ret != LDB_SUCCESS) {
1689                 ldb_asprintf_errstring(ldb,
1690                         "setup_io: "
1691                         "it's only allowed to set the old password once!");
1692                 return ret;
1693         }
1694
1695         /* this rather strange looking piece of code is there to
1696            handle a ldap client setting a password remotely using the
1697            unicodePwd ldap field. The syntax is that the password is
1698            in UTF-16LE, with a " at either end. Unfortunately the
1699            unicodePwd field is also used to store the nt hashes
1700            internally in Samba, and is used in the nt hash format on
1701            the wire in DRS replication, so we have a single name for
1702            two distinct values. The code below leaves us with a small
1703            chance (less than 1 in 2^32) of a mixup, if someone manages
1704            to create a MD4 hash which starts and ends in 0x22 0x00, as
1705            that would then be treated as a UTF16 password rather than
1706            a nthash */
1707
1708         ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "unicodePwd",
1709                 &quoted_utf16, &old_quoted_utf16);
1710         if (ret != LDB_SUCCESS) {
1711                 ldb_asprintf_errstring(ldb,
1712                         "setup_io: "
1713                         "it's only allowed to set the old password once!");
1714                 return ret;
1715         }
1716
1717         /* Checks and converts the actual "unicodePwd" attribute */
1718         if (quoted_utf16 &&
1719             quoted_utf16->length >= 4 &&
1720             quoted_utf16->data[0] == '"' &&
1721             quoted_utf16->data[1] == 0 &&
1722             quoted_utf16->data[quoted_utf16->length-2] == '"' &&
1723             quoted_utf16->data[quoted_utf16->length-1] == 0) {
1724                 struct ldb_val *quoted_utf16_2;
1725
1726                 if (io->n.cleartext_utf16) {
1727                         /* refuse the change if someone wants to change with
1728                            with both UTF16 possibilities at the same time... */
1729                         ldb_asprintf_errstring(ldb,
1730                                 "setup_io: "
1731                                 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
1732                         return LDB_ERR_UNWILLING_TO_PERFORM;
1733                 }
1734
1735                 /*
1736                  * adapt the quoted UTF16 string to be a real
1737                  * cleartext one
1738                  */
1739                 quoted_utf16_2 = talloc(io->ac, struct ldb_val);
1740                 if (quoted_utf16_2 == NULL) {
1741                         ldb_oom(ldb);
1742                         return LDB_ERR_OPERATIONS_ERROR;
1743                 }
1744
1745                 quoted_utf16_2->data = quoted_utf16->data + 2;
1746                 quoted_utf16_2->length = quoted_utf16->length-4;
1747                 io->n.cleartext_utf16 = quoted_utf16_2;
1748                 io->n.nt_hash = NULL;
1749
1750         } else if (quoted_utf16) {
1751                 /* We have only the hash available -> so no plaintext here */
1752                 if (!ac->hash_values) {
1753                         /* refuse the change if someone wants to change
1754                            the hash without control specified... */
1755                         ldb_asprintf_errstring(ldb,
1756                                 "setup_io: "
1757                                 "it's not allowed to set the NT hash password directly'");
1758                         /* this looks odd but this is what Windows does:
1759                            returns "UNWILLING_TO_PERFORM" on wrong
1760                            password sets and "CONSTRAINT_VIOLATION" on
1761                            wrong password changes. */
1762                         if (old_quoted_utf16 == NULL) {
1763                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1764                         }
1765
1766                         return LDB_ERR_CONSTRAINT_VIOLATION;
1767                 }
1768
1769                 io->n.nt_hash = talloc(io->ac, struct samr_Password);
1770                 memcpy(io->n.nt_hash->hash, quoted_utf16->data,
1771                        MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
1772         }
1773
1774         /* Checks and converts the previous "unicodePwd" attribute */
1775         if (old_quoted_utf16 &&
1776             old_quoted_utf16->length >= 4 &&
1777             old_quoted_utf16->data[0] == '"' &&
1778             old_quoted_utf16->data[1] == 0 &&
1779             old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
1780             old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
1781                 struct ldb_val *old_quoted_utf16_2;
1782
1783                 if (io->og.cleartext_utf16) {
1784                         /* refuse the change if someone wants to change with
1785                            both UTF16 possibilities at the same time... */
1786                         ldb_asprintf_errstring(ldb,
1787                                 "setup_io: "
1788                                 "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
1789                         return LDB_ERR_UNWILLING_TO_PERFORM;
1790                 }
1791
1792                 /*
1793                  * adapt the quoted UTF16 string to be a real
1794                  * cleartext one
1795                  */
1796                 old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
1797                 if (old_quoted_utf16_2 == NULL) {
1798                         ldb_oom(ldb);
1799                         return LDB_ERR_OPERATIONS_ERROR;
1800                 }
1801
1802                 old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
1803                 old_quoted_utf16_2->length = old_quoted_utf16->length-4;
1804
1805                 io->og.cleartext_utf16 = old_quoted_utf16_2;
1806                 io->og.nt_hash = NULL;
1807         } else if (old_quoted_utf16) {
1808                 /* We have only the hash available -> so no plaintext here */
1809                 if (!ac->hash_values) {
1810                         /* refuse the change if someone wants to change
1811                            the hash without control specified... */
1812                         ldb_asprintf_errstring(ldb,
1813                                 "setup_io: "
1814                                 "it's not allowed to set the NT hash password directly'");
1815                         return LDB_ERR_UNWILLING_TO_PERFORM;
1816                 }
1817
1818                 io->og.nt_hash = talloc(io->ac, struct samr_Password);
1819                 memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
1820                        MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
1821         }
1822
1823         /* Handles the "dBCSPwd" attribute (LM hash) */
1824         io->n.lm_hash = NULL; io->og.lm_hash = NULL;
1825         ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "dBCSPwd",
1826                 &lm_hash, &old_lm_hash);
1827         if (ret != LDB_SUCCESS) {
1828                 ldb_asprintf_errstring(ldb,
1829                         "setup_io: "
1830                         "it's only allowed to set the old password once!");
1831                 return ret;
1832         }
1833
1834         if (((lm_hash != NULL) || (old_lm_hash != NULL)) && (!ac->hash_values)) {
1835                 /* refuse the change if someone wants to change the hash
1836                    without control specified... */
1837                 ldb_asprintf_errstring(ldb,
1838                         "setup_io: "
1839                         "it's not allowed to set the LM hash password directly'");
1840                 return LDB_ERR_UNWILLING_TO_PERFORM;
1841         }
1842
1843         if (lp_lanman_auth(lp_ctx) && (lm_hash != NULL)) {
1844                 io->n.lm_hash = talloc(io->ac, struct samr_Password);
1845                 memcpy(io->n.lm_hash->hash, lm_hash->data, MIN(lm_hash->length,
1846                        sizeof(io->n.lm_hash->hash)));
1847         }
1848         if (lp_lanman_auth(lp_ctx) && (old_lm_hash != NULL)) {
1849                 io->og.lm_hash = talloc(io->ac, struct samr_Password);
1850                 memcpy(io->og.lm_hash->hash, old_lm_hash->data, MIN(old_lm_hash->length,
1851                        sizeof(io->og.lm_hash->hash)));
1852         }
1853
1854         /* refuse the change if someone wants to change the clear-
1855            text and supply his own hashes at the same time... */
1856         if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
1857                         && (io->n.nt_hash || io->n.lm_hash)) {
1858                 ldb_asprintf_errstring(ldb,
1859                         "setup_io: "
1860                         "it's only allowed to set the password in form of cleartext attributes or as hashes");
1861                 return LDB_ERR_UNWILLING_TO_PERFORM;
1862         }
1863
1864         /* refuse the change if someone wants to change the password
1865            using both plaintext methods (UTF8 and UTF16) at the same time... */
1866         if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
1867                 ldb_asprintf_errstring(ldb,
1868                         "setup_io: "
1869                         "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
1870                 return LDB_ERR_UNWILLING_TO_PERFORM;
1871         }
1872
1873         /* refuse the change if someone tries to set/change the password by
1874          * the lanman hash alone and we've deactivated that mechanism. This
1875          * would end in an account without any password! */
1876         if ((!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
1877             && (!io->n.nt_hash) && (!io->n.lm_hash)) {
1878                 ldb_asprintf_errstring(ldb,
1879                         "setup_io: "
1880                         "The password change/set operations performed using the LAN Manager hash alone are deactivated!");
1881                 return LDB_ERR_UNWILLING_TO_PERFORM;
1882         }
1883
1884         /* refuse the change if someone wants to compare against a plaintext
1885            or hash at the same time for a "password modify" operation... */
1886         if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
1887             && (io->og.nt_hash || io->og.lm_hash)) {
1888                 ldb_asprintf_errstring(ldb,
1889                         "setup_io: "
1890                         "it's only allowed to provide the old password in form of cleartext attributes or as hashes");
1891                 return LDB_ERR_UNWILLING_TO_PERFORM;
1892         }
1893
1894         /* refuse the change if someone wants to compare against both
1895          * plaintexts at the same time for a "password modify" operation... */
1896         if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
1897                 ldb_asprintf_errstring(ldb,
1898                         "setup_io: "
1899                         "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
1900                 return LDB_ERR_UNWILLING_TO_PERFORM;
1901         }
1902
1903         /* refuse the change if someone wants to compare against both
1904          * hashes at the same time for a "password modify" operation... */
1905         if (io->og.nt_hash && io->og.lm_hash) {
1906                 ldb_asprintf_errstring(ldb,
1907                         "setup_io: "
1908                         "it's only allowed to provide the old password in hash format as 'unicodePwd' or as 'dBCSPwd'");
1909                 return LDB_ERR_UNWILLING_TO_PERFORM;
1910         }
1911
1912         /* Decides if we have a password modify or password reset operation */
1913         if (ac->req->operation == LDB_ADD) {
1914                 /* On "add" we have only "password reset" */
1915                 ac->pwd_reset = true;
1916         } else if (ac->req->operation == LDB_MODIFY) {
1917                 if (io->og.cleartext_utf8 || io->og.cleartext_utf16
1918                     || io->og.nt_hash || io->og.lm_hash
1919                     || ac->change_old_pw_checked) {
1920                         /* If we have an old password or the "change old
1921                          * password checked" control specified then for sure it
1922                          * is a user "password change" */
1923                         ac->pwd_reset = false;
1924                 } else {
1925                         /* Otherwise we have also here a "password reset" */
1926                         ac->pwd_reset = true;
1927                 }
1928         } else {
1929                 /* this shouldn't happen */
1930                 return LDB_ERR_OPERATIONS_ERROR;
1931         }
1932
1933         return LDB_SUCCESS;
1934 }
1935
1936 static struct ph_context *ph_init_context(struct ldb_module *module,
1937                                           struct ldb_request *req)
1938 {
1939         struct ldb_context *ldb;
1940         struct ph_context *ac;
1941
1942         ldb = ldb_module_get_ctx(module);
1943
1944         ac = talloc_zero(req, struct ph_context);
1945         if (ac == NULL) {
1946                 ldb_set_errstring(ldb, "Out of Memory");
1947                 return NULL;
1948         }
1949
1950         ac->module = module;
1951         ac->req = req;
1952
1953         return ac;
1954 }
1955
1956 static void ph_apply_controls(struct ph_context *ac)
1957 {
1958         struct ldb_control *ctrl;
1959
1960         ac->change_status = false;
1961         ctrl = ldb_request_get_control(ac->req,
1962                                        DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
1963         if (ctrl != NULL) {
1964                 ac->change_status = true;
1965
1966                 /* Mark the "change status" control as uncritical (done) */
1967                 ctrl->critical = false;
1968         }
1969
1970         ac->hash_values = false;
1971         ctrl = ldb_request_get_control(ac->req,
1972                                        DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
1973         if (ctrl != NULL) {
1974                 ac->hash_values = true;
1975
1976                 /* Mark the "hash values" control as uncritical (done) */
1977                 ctrl->critical = false;
1978         }
1979
1980         ac->change_old_pw_checked = false;
1981         ctrl = ldb_request_get_control(ac->req,
1982                                        DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID);
1983         if (ctrl != NULL) {
1984                 ac->change_old_pw_checked = true;
1985
1986                 /* Mark the "change old password checked" control as uncritical
1987                  * (done) */
1988                 ctrl->critical = false;
1989         }
1990 }
1991
1992 static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
1993 {
1994         struct ph_context *ac;
1995
1996         ac = talloc_get_type(req->context, struct ph_context);
1997
1998         if (!ares) {
1999                 return ldb_module_done(ac->req, NULL, NULL,
2000                                         LDB_ERR_OPERATIONS_ERROR);
2001         }
2002
2003         if (ares->type == LDB_REPLY_REFERRAL) {
2004                 return ldb_module_send_referral(ac->req, ares->referral);
2005         }
2006
2007         if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2008                 /* On success and trivial errors a status control is being
2009                  * added (used for example by the "samdb_set_password" call) */
2010                 ldb_reply_add_control(ares,
2011                                       DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2012                                       false,
2013                                       ac->status);
2014         }
2015
2016         if (ares->error != LDB_SUCCESS) {
2017                 return ldb_module_done(ac->req, ares->controls,
2018                                         ares->response, ares->error);
2019         }
2020
2021         if (ares->type != LDB_REPLY_DONE) {
2022                 talloc_free(ares);
2023                 return ldb_module_done(ac->req, NULL, NULL,
2024                                         LDB_ERR_OPERATIONS_ERROR);
2025         }
2026
2027         return ldb_module_done(ac->req, ares->controls,
2028                                 ares->response, ares->error);
2029 }
2030
2031 static int password_hash_add_do_add(struct ph_context *ac);
2032 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
2033 static int password_hash_mod_search_self(struct ph_context *ac);
2034 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
2035 static int password_hash_mod_do_mod(struct ph_context *ac);
2036
2037 static int get_domain_data_callback(struct ldb_request *req,
2038                                     struct ldb_reply *ares)
2039 {
2040         struct ldb_context *ldb;
2041         struct ph_context *ac;
2042         struct loadparm_context *lp_ctx;
2043         int ret;
2044
2045         ac = talloc_get_type(req->context, struct ph_context);
2046         ldb = ldb_module_get_ctx(ac->module);
2047
2048         if (!ares) {
2049                 ret = LDB_ERR_OPERATIONS_ERROR;
2050                 goto done;
2051         }
2052         if (ares->error != LDB_SUCCESS) {
2053                 return ldb_module_done(ac->req, ares->controls,
2054                                         ares->response, ares->error);
2055         }
2056
2057         switch (ares->type) {
2058         case LDB_REPLY_ENTRY:
2059                 if (ac->status != NULL) {
2060                         talloc_free(ares);
2061
2062                         ldb_set_errstring(ldb, "Too many results");
2063                         ret = LDB_ERR_OPERATIONS_ERROR;
2064                         goto done;
2065                 }
2066
2067                 /* Setup the "status" structure (used as control later) */
2068                 ac->status = talloc_zero(ac->req,
2069                                          struct dsdb_control_password_change_status);
2070                 if (ac->status == NULL) {
2071                         talloc_free(ares);
2072
2073                         ldb_oom(ldb);
2074                         ret = LDB_ERR_OPERATIONS_ERROR;
2075                         goto done;
2076                 }
2077
2078                 /* Setup the "domain data" structure */
2079                 ac->status->domain_data.pwdProperties = samdb_result_uint(ares->message, "pwdProperties", -1);
2080                 ac->status->domain_data.pwdHistoryLength = samdb_result_uint(ares->message, "pwdHistoryLength", -1);
2081                 ac->status->domain_data.maxPwdAge = samdb_result_int64(ares->message, "maxPwdAge", -1);
2082                 ac->status->domain_data.minPwdAge = samdb_result_int64(ares->message, "minPwdAge", -1);
2083                 ac->status->domain_data.minPwdLength = samdb_result_uint(ares->message, "minPwdLength", -1);
2084                 ac->status->domain_data.store_cleartext =
2085                         ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
2086
2087                 talloc_free(ares);
2088
2089                 /* For a domain DN, this puts things in dotted notation */
2090                 /* For builtin domains, this will give details for the host,
2091                  * but that doesn't really matter, as it's just used for salt
2092                  * and kerberos principals, which don't exist here */
2093
2094                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2095                                          struct loadparm_context);
2096
2097                 ac->status->domain_data.dns_domain = lp_dnsdomain(lp_ctx);
2098                 ac->status->domain_data.realm = lp_realm(lp_ctx);
2099                 ac->status->domain_data.netbios_domain = lp_sam_name(lp_ctx);
2100
2101                 ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2102
2103                 ret = LDB_SUCCESS;
2104                 break;
2105
2106         case LDB_REPLY_REFERRAL:
2107                 /* ignore */
2108                 talloc_free(ares);
2109                 ret = LDB_SUCCESS;
2110                 break;
2111
2112         case LDB_REPLY_DONE:
2113                 talloc_free(ares);
2114                 /* call the next step */
2115                 switch (ac->req->operation) {
2116                 case LDB_ADD:
2117                         ret = password_hash_add_do_add(ac);
2118                         break;
2119
2120                 case LDB_MODIFY:
2121                         ret = password_hash_mod_do_mod(ac);
2122                         break;
2123
2124                 default:
2125                         ret = LDB_ERR_OPERATIONS_ERROR;
2126                         break;
2127                 }
2128                 break;
2129         }
2130
2131 done:
2132         if (ret != LDB_SUCCESS) {
2133                 struct ldb_reply *new_ares;
2134
2135                 new_ares = talloc_zero(ac->req, struct ldb_reply);
2136                 if (new_ares == NULL) {
2137                         ldb_oom(ldb);
2138                         return ldb_module_done(ac->req, NULL, NULL,
2139                                                LDB_ERR_OPERATIONS_ERROR);
2140                 }
2141
2142                 new_ares->error = ret;
2143                 if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
2144                         /* On success and trivial errors a status control is being
2145                          * added (used for example by the "samdb_set_password" call) */
2146                         ldb_reply_add_control(new_ares,
2147                                               DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2148                                               false,
2149                                               ac->status);
2150                 }
2151
2152                 return ldb_module_done(ac->req, new_ares->controls,
2153                                        new_ares->response, new_ares->error);
2154         }
2155
2156         return LDB_SUCCESS;
2157 }
2158
2159 static int build_domain_data_request(struct ph_context *ac)
2160 {
2161         /* attrs[] is returned from this function in
2162            ac->dom_req->op.search.attrs, so it must be static, as
2163            otherwise the compiler can put it on the stack */
2164         struct ldb_context *ldb;
2165         static const char * const attrs[] = { "pwdProperties",
2166                                               "pwdHistoryLength",
2167                                               "maxPwdAge",
2168                                               "minPwdAge",
2169                                               "minPwdLength",
2170                                               NULL };
2171
2172         ldb = ldb_module_get_ctx(ac->module);
2173
2174         return ldb_build_search_req(&ac->dom_req, ldb, ac,
2175                                     ldb_get_default_basedn(ldb),
2176                                     LDB_SCOPE_BASE,
2177                                     NULL, attrs,
2178                                     NULL,
2179                                     ac, get_domain_data_callback,
2180                                     ac->req);
2181 }
2182
2183 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
2184 {
2185         struct ldb_context *ldb;
2186         struct ph_context *ac;
2187         struct ldb_message_element *userPasswordAttr, *clearTextPasswordAttr,
2188                 *ntAttr, *lmAttr;
2189         int ret;
2190
2191         ldb = ldb_module_get_ctx(module);
2192
2193         ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
2194
2195         if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
2196                 return ldb_next_request(module, req);
2197         }
2198
2199         /* If the caller is manipulating the local passwords directly, let them pass */
2200         if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
2201                                 req->op.add.message->dn) == 0) {
2202                 return ldb_next_request(module, req);
2203         }
2204
2205         /* nobody must touch password histories and 'supplementalCredentials' */
2206         if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
2207                 return LDB_ERR_UNWILLING_TO_PERFORM;
2208         }
2209         if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
2210                 return LDB_ERR_UNWILLING_TO_PERFORM;
2211         }
2212         if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
2213                 return LDB_ERR_UNWILLING_TO_PERFORM;
2214         }
2215
2216         /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
2217          * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes. */
2218
2219         userPasswordAttr = ldb_msg_find_element(req->op.add.message, "userPassword");
2220         clearTextPasswordAttr = ldb_msg_find_element(req->op.add.message, "clearTextPassword");
2221         ntAttr = ldb_msg_find_element(req->op.add.message, "unicodePwd");
2222         lmAttr = ldb_msg_find_element(req->op.add.message, "dBCSPwd");
2223
2224         if ((!userPasswordAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
2225                 return ldb_next_request(module, req);
2226         }
2227
2228         /* Make sure we are performing the password set action on a (for us)
2229          * valid object. Those are instances of either "user" and/or
2230          * "inetOrgPerson". Otherwise continue with the submodules. */
2231         if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
2232                 && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
2233
2234                 if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
2235                         ldb_set_errstring(ldb,
2236                                           "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
2237                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
2238                 }
2239
2240                 return ldb_next_request(module, req);
2241         }
2242
2243         ac = ph_init_context(module, req);
2244         if (ac == NULL) {
2245                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
2246                 return LDB_ERR_OPERATIONS_ERROR;
2247         }
2248         ph_apply_controls(ac);
2249
2250         /* get user domain data */
2251         ret = build_domain_data_request(ac);
2252         if (ret != LDB_SUCCESS) {
2253                 return ret;
2254         }
2255
2256         return ldb_next_request(module, ac->dom_req);
2257 }
2258
2259 static int password_hash_add_do_add(struct ph_context *ac)
2260 {
2261         struct ldb_context *ldb;
2262         struct ldb_request *down_req;
2263         struct ldb_message *msg;
2264         struct setup_password_fields_io io;
2265         int ret;
2266
2267         /* Prepare the internal data structure containing the passwords */
2268         ret = setup_io(ac, ac->req->op.add.message, ac->req->op.add.message, &io);
2269         if (ret != LDB_SUCCESS) {
2270                 return ret;
2271         }
2272
2273         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
2274         if (msg == NULL) {
2275                 return LDB_ERR_OPERATIONS_ERROR;
2276         }
2277
2278         /* remove attributes that we just read into 'io' */
2279         ldb_msg_remove_attr(msg, "userPassword");
2280         ldb_msg_remove_attr(msg, "clearTextPassword");
2281         ldb_msg_remove_attr(msg, "unicodePwd");
2282         ldb_msg_remove_attr(msg, "dBCSPwd");
2283         ldb_msg_remove_attr(msg, "pwdLastSet");
2284
2285         ldb = ldb_module_get_ctx(ac->module);
2286
2287         ret = setup_password_fields(&io);
2288         if (ret != LDB_SUCCESS) {
2289                 return ret;
2290         }
2291
2292         ret = check_password_restrictions(&io);
2293         if (ret != LDB_SUCCESS) {
2294                 return ret;
2295         }
2296
2297         if (io.g.nt_hash) {
2298                 ret = samdb_msg_add_hash(ldb, ac, msg,
2299                                          "unicodePwd", io.g.nt_hash);
2300                 if (ret != LDB_SUCCESS) {
2301                         return ret;
2302                 }
2303         }
2304         if (io.g.lm_hash) {
2305                 ret = samdb_msg_add_hash(ldb, ac, msg,
2306                                          "dBCSPwd", io.g.lm_hash);
2307                 if (ret != LDB_SUCCESS) {
2308                         return ret;
2309                 }
2310         }
2311         if (io.g.nt_history_len > 0) {
2312                 ret = samdb_msg_add_hashes(ac, msg,
2313                                            "ntPwdHistory",
2314                                            io.g.nt_history,
2315                                            io.g.nt_history_len);
2316                 if (ret != LDB_SUCCESS) {
2317                         return ret;
2318                 }
2319         }
2320         if (io.g.lm_history_len > 0) {
2321                 ret = samdb_msg_add_hashes(ac, msg,
2322                                            "lmPwdHistory",
2323                                            io.g.lm_history,
2324                                            io.g.lm_history_len);
2325                 if (ret != LDB_SUCCESS) {
2326                         return ret;
2327                 }
2328         }
2329         if (io.g.supplemental.length > 0) {
2330                 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2331                                         &io.g.supplemental, NULL);
2332                 if (ret != LDB_SUCCESS) {
2333                         return ret;
2334                 }
2335         }
2336         ret = samdb_msg_add_uint64(ldb, ac, msg,
2337                                    "pwdLastSet",
2338                                    io.g.last_set);
2339         if (ret != LDB_SUCCESS) {
2340                 return ret;
2341         }
2342
2343         ret = ldb_build_add_req(&down_req, ldb, ac,
2344                                 msg,
2345                                 ac->req->controls,
2346                                 ac, ph_op_callback,
2347                                 ac->req);
2348         if (ret != LDB_SUCCESS) {
2349                 return ret;
2350         }
2351
2352         return ldb_next_request(ac->module, down_req);
2353 }
2354
2355 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
2356 {
2357         struct ldb_context *ldb;
2358         struct ph_context *ac;
2359         const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
2360                 "unicodePwd", "dBCSPwd", NULL }, **l;
2361         unsigned int attr_cnt, del_attr_cnt, add_attr_cnt, rep_attr_cnt;
2362         struct ldb_message_element *passwordAttr;
2363         struct ldb_message *msg;
2364         struct ldb_request *down_req;
2365         int ret;
2366
2367         ldb = ldb_module_get_ctx(module);
2368
2369         ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
2370
2371         if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
2372                 return ldb_next_request(module, req);
2373         }
2374         
2375         /* If the caller is manipulating the local passwords directly, let them pass */
2376         if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
2377                                 req->op.mod.message->dn) == 0) {
2378                 return ldb_next_request(module, req);
2379         }
2380
2381         /* nobody must touch password histories and 'supplementalCredentials' */
2382         if (ldb_msg_find_element(req->op.mod.message, "ntPwdHistory")) {
2383                 return LDB_ERR_UNWILLING_TO_PERFORM;
2384         }
2385         if (ldb_msg_find_element(req->op.mod.message, "lmPwdHistory")) {
2386                 return LDB_ERR_UNWILLING_TO_PERFORM;
2387         }
2388         if (ldb_msg_find_element(req->op.mod.message, "supplementalCredentials")) {
2389                 return LDB_ERR_UNWILLING_TO_PERFORM;
2390         }
2391
2392         /* If no part of this touches the 'userPassword' OR 'clearTextPassword'
2393          * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
2394          * For password changes/set there should be a 'delete' or a 'modify'
2395          * on these attributes. */
2396         attr_cnt = 0;
2397         for (l = passwordAttrs; *l != NULL; l++) {
2398                 if (ldb_msg_find_element(req->op.mod.message, *l) != NULL) {
2399                         ++attr_cnt;
2400                 }
2401         }
2402         if (attr_cnt == 0) {
2403                 return ldb_next_request(module, req);
2404         }
2405
2406         ac = ph_init_context(module, req);
2407         if (!ac) {
2408                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
2409                 return LDB_ERR_OPERATIONS_ERROR;
2410         }
2411         ph_apply_controls(ac);
2412
2413         /* use a new message structure so that we can modify it */
2414         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2415         if (msg == NULL) {
2416                 ldb_oom(ldb);
2417                 return LDB_ERR_OPERATIONS_ERROR;
2418         }
2419
2420         /* - check for single-valued password attributes
2421          *   (if not return "CONSTRAINT_VIOLATION")
2422          * - check that for a password change operation one add and one delete
2423          *   operation exists
2424          *   (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
2425          * - check that a password change and a password set operation cannot
2426          *   be mixed
2427          *   (if not return "UNWILLING_TO_PERFORM")
2428          * - remove all password attributes modifications from the first change
2429          *   operation (anything without the passwords) - we will make the real
2430          *   modification later */
2431         del_attr_cnt = 0;
2432         add_attr_cnt = 0;
2433         rep_attr_cnt = 0;
2434         for (l = passwordAttrs; *l != NULL; l++) {
2435                 while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
2436                         if (passwordAttr->flags == LDB_FLAG_MOD_DELETE) {
2437                                 ++del_attr_cnt;
2438                         }
2439                         if (passwordAttr->flags == LDB_FLAG_MOD_ADD) {
2440                                 ++add_attr_cnt;
2441                         }
2442                         if (passwordAttr->flags == LDB_FLAG_MOD_REPLACE) {
2443                                 ++rep_attr_cnt;
2444                         }
2445                         if ((passwordAttr->num_values != 1) &&
2446                             (passwordAttr->flags != LDB_FLAG_MOD_REPLACE)) {
2447                                 talloc_free(ac);
2448                                 ldb_asprintf_errstring(ldb,
2449                                                        "'%s' attributes must have exactly one value!",
2450                                                        *l);
2451                                 return LDB_ERR_CONSTRAINT_VIOLATION;
2452                         }
2453                         ldb_msg_remove_element(msg, passwordAttr);
2454                 }
2455         }
2456         if ((del_attr_cnt > 0) && (add_attr_cnt == 0)) {
2457                 talloc_free(ac);
2458                 ldb_set_errstring(ldb,
2459                                   "Only the delete action for a password change specified!");
2460                 return LDB_ERR_CONSTRAINT_VIOLATION;
2461         }
2462         if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
2463                 talloc_free(ac);
2464                 ldb_set_errstring(ldb,
2465                                   "Only the add action for a password change specified!");
2466                 return LDB_ERR_UNWILLING_TO_PERFORM;
2467         }
2468         if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
2469                 talloc_free(ac);
2470                 ldb_set_errstring(ldb,
2471                                   "Only one delete and one add action for a password change allowed!");
2472                 return LDB_ERR_UNWILLING_TO_PERFORM;
2473         }
2474         if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
2475                 talloc_free(ac);
2476                 ldb_set_errstring(ldb,
2477                                   "Either a password change or a password set operation is allowed!");
2478                 return LDB_ERR_UNWILLING_TO_PERFORM;
2479         }
2480
2481         /* if there was nothing else to be modified skip to next step */
2482         if (msg->num_elements == 0) {
2483                 return password_hash_mod_search_self(ac);
2484         }
2485
2486         ret = ldb_build_mod_req(&down_req, ldb, ac,
2487                                 msg,
2488                                 req->controls,
2489                                 ac, ph_modify_callback,
2490                                 req);
2491         if (ret != LDB_SUCCESS) {
2492                 return ret;
2493         }
2494
2495         return ldb_next_request(module, down_req);
2496 }
2497
2498 static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
2499 {
2500         struct ph_context *ac;
2501
2502         ac = talloc_get_type(req->context, struct ph_context);
2503
2504         if (!ares) {
2505                 return ldb_module_done(ac->req, NULL, NULL,
2506                                         LDB_ERR_OPERATIONS_ERROR);
2507         }
2508
2509         if (ares->type == LDB_REPLY_REFERRAL) {
2510                 return ldb_module_send_referral(ac->req, ares->referral);
2511         }
2512
2513         if (ares->error != LDB_SUCCESS) {
2514                 return ldb_module_done(ac->req, ares->controls,
2515                                         ares->response, ares->error);
2516         }
2517
2518         if (ares->type != LDB_REPLY_DONE) {
2519                 talloc_free(ares);
2520                 return ldb_module_done(ac->req, NULL, NULL,
2521                                         LDB_ERR_OPERATIONS_ERROR);
2522         }
2523
2524         talloc_free(ares);
2525
2526         return password_hash_mod_search_self(ac);
2527 }
2528
2529 static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
2530 {
2531         struct ldb_context *ldb;
2532         struct ph_context *ac;
2533         int ret;
2534
2535         ac = talloc_get_type(req->context, struct ph_context);
2536         ldb = ldb_module_get_ctx(ac->module);
2537
2538         if (!ares) {
2539                 ret = LDB_ERR_OPERATIONS_ERROR;
2540                 goto done;
2541         }
2542         if (ares->error != LDB_SUCCESS) {
2543                 return ldb_module_done(ac->req, ares->controls,
2544                                         ares->response, ares->error);
2545         }
2546
2547         /* we are interested only in the single reply (base search) */
2548         switch (ares->type) {
2549         case LDB_REPLY_ENTRY:
2550                 /* Make sure we are performing the password change action on a
2551                  * (for us) valid object. Those are instances of either "user"
2552                  * and/or "inetOrgPerson". Otherwise continue with the
2553                  * submodules. */
2554                 if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
2555                         && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
2556                         talloc_free(ares);
2557
2558                         if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
2559                                 ldb_set_errstring(ldb,
2560                                                   "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
2561                                 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
2562                                 goto done;
2563                         }
2564
2565                         ret = ldb_next_request(ac->module, ac->req);
2566                         goto done;
2567                 }
2568
2569                 if (ac->search_res != NULL) {
2570                         talloc_free(ares);
2571
2572                         ldb_set_errstring(ldb, "Too many results");
2573                         ret = LDB_ERR_OPERATIONS_ERROR;
2574                         goto done;
2575                 }
2576
2577                 ac->search_res = talloc_steal(ac, ares);
2578                 ret = LDB_SUCCESS;
2579                 break;
2580
2581         case LDB_REPLY_REFERRAL:
2582                 /* ignore anything else for now */
2583                 talloc_free(ares);
2584                 ret = LDB_SUCCESS;
2585                 break;
2586
2587         case LDB_REPLY_DONE:
2588                 talloc_free(ares);
2589
2590                 /* get user domain data */
2591                 ret = build_domain_data_request(ac);
2592                 if (ret != LDB_SUCCESS) {
2593                         return ldb_module_done(ac->req, NULL, NULL, ret);
2594                 }
2595
2596                 ret = ldb_next_request(ac->module, ac->dom_req);
2597                 break;
2598         }
2599
2600 done:
2601         if (ret != LDB_SUCCESS) {
2602                 return ldb_module_done(ac->req, NULL, NULL, ret);
2603         }
2604
2605         return LDB_SUCCESS;
2606 }
2607
2608 static int password_hash_mod_search_self(struct ph_context *ac)
2609 {
2610         struct ldb_context *ldb;
2611         static const char * const attrs[] = { "objectClass",
2612                                               "userAccountControl",
2613                                               "pwdLastSet",
2614                                               "sAMAccountName",
2615                                               "objectSid",
2616                                               "userPrincipalName",
2617                                               "supplementalCredentials",
2618                                               "lmPwdHistory",
2619                                               "ntPwdHistory",
2620                                               "dBCSPwd",
2621                                               "unicodePwd",
2622                                               NULL };
2623         struct ldb_request *search_req;
2624         int ret;
2625
2626         ldb = ldb_module_get_ctx(ac->module);
2627
2628         ret = ldb_build_search_req(&search_req, ldb, ac,
2629                                    ac->req->op.mod.message->dn,
2630                                    LDB_SCOPE_BASE,
2631                                    "(objectclass=*)",
2632                                    attrs,
2633                                    NULL,
2634                                    ac, ph_mod_search_callback,
2635                                    ac->req);
2636
2637         if (ret != LDB_SUCCESS) {
2638                 return ret;
2639         }
2640
2641         return ldb_next_request(ac->module, search_req);
2642 }
2643
2644 static int password_hash_mod_do_mod(struct ph_context *ac)
2645 {
2646         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2647         struct loadparm_context *lp_ctx =
2648                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2649                                          struct loadparm_context);
2650         struct ldb_request *mod_req;
2651         struct ldb_message *msg;
2652         const struct ldb_message *orig_msg, *searched_msg;
2653         struct setup_password_fields_io io;
2654         int ret;
2655         NTSTATUS status;
2656
2657         /* use a new message structure so that we can modify it */
2658         msg = ldb_msg_new(ac);
2659         if (msg == NULL) {
2660                 return LDB_ERR_OPERATIONS_ERROR;
2661         }
2662
2663         /* modify dn */
2664         msg->dn = ac->req->op.mod.message->dn;
2665
2666         orig_msg = ac->req->op.mod.message;
2667         searched_msg = ac->search_res->message;
2668
2669         /* Prepare the internal data structure containing the passwords */
2670         ret = setup_io(ac, orig_msg, searched_msg, &io);
2671         if (ret != LDB_SUCCESS) {
2672                 return ret;
2673         }
2674         
2675         /* Get the old password from the database */
2676         status = samdb_result_passwords(io.ac,
2677                                         lp_ctx,
2678                                         discard_const_p(struct ldb_message, searched_msg),
2679                                         &io.o.lm_hash, &io.o.nt_hash);
2680         if (!NT_STATUS_IS_OK(status)) {
2681                 return LDB_ERR_OPERATIONS_ERROR;
2682         }
2683
2684         io.o.nt_history_len             = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
2685         io.o.lm_history_len             = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
2686         io.o.supplemental               = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
2687
2688         ret = setup_password_fields(&io);
2689         if (ret != LDB_SUCCESS) {
2690                 return ret;
2691         }
2692
2693         ret = check_password_restrictions(&io);
2694         if (ret != LDB_SUCCESS) {
2695                 return ret;
2696         }
2697
2698         /* make sure we replace all the old attributes */
2699         ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
2700         ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
2701         ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2702         ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
2703         ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
2704         ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
2705
2706         if (io.g.nt_hash) {
2707                 ret = samdb_msg_add_hash(ldb, ac, msg,
2708                                          "unicodePwd", io.g.nt_hash);
2709                 if (ret != LDB_SUCCESS) {
2710                         return ret;
2711                 }
2712         }
2713         if (io.g.lm_hash) {
2714                 ret = samdb_msg_add_hash(ldb, ac, msg,
2715                                          "dBCSPwd", io.g.lm_hash);
2716                 if (ret != LDB_SUCCESS) {
2717                         return ret;
2718                 }
2719         }
2720         if (io.g.nt_history_len > 0) {
2721                 ret = samdb_msg_add_hashes(ac, msg,
2722                                            "ntPwdHistory",
2723                                            io.g.nt_history,
2724                                            io.g.nt_history_len);
2725                 if (ret != LDB_SUCCESS) {
2726                         return ret;
2727                 }
2728         }
2729         if (io.g.lm_history_len > 0) {
2730                 ret = samdb_msg_add_hashes(ac, msg,
2731                                            "lmPwdHistory",
2732                                            io.g.lm_history,
2733                                            io.g.lm_history_len);
2734                 if (ret != LDB_SUCCESS) {
2735                         return ret;
2736                 }
2737         }
2738         if (io.g.supplemental.length > 0) {
2739                 ret = ldb_msg_add_value(msg, "supplementalCredentials",
2740                                         &io.g.supplemental, NULL);
2741                 if (ret != LDB_SUCCESS) {
2742                         return ret;
2743                 }
2744         }
2745         ret = samdb_msg_add_uint64(ldb, ac, msg,
2746                                    "pwdLastSet",
2747                                    io.g.last_set);
2748         if (ret != LDB_SUCCESS) {
2749                 return ret;
2750         }
2751
2752         ret = ldb_build_mod_req(&mod_req, ldb, ac,
2753                                 msg,
2754                                 ac->req->controls,
2755                                 ac, ph_op_callback,
2756                                 ac->req);
2757         if (ret != LDB_SUCCESS) {
2758                 return ret;
2759         }
2760
2761         return ldb_next_request(ac->module, mod_req);
2762 }
2763
2764 _PUBLIC_ const struct ldb_module_ops ldb_password_hash_module_ops = {
2765         .name          = "password_hash",
2766         .add           = password_hash_add,
2767         .modify        = password_hash_modify
2768 };