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