password_hash: order the supplementalCredentials Packages in the same order like...
[metze/samba/wip.git] / source4 / dsdb / samdb / ldb_modules / password_hash.c
1 /* 
2    ldb database module
3
4    Copyright (C) Simo Sorce  2004-2006
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Stefan Metzmacher 2007
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /*
24  *  Name: ldb
25  *
26  *  Component: ldb password_hash module
27  *
28  *  Description: correctly update hash values based on changes to userPassword and friends
29  *
30  *  Author: Andrew Bartlett
31  *  Author: Stefan Metzmacher
32  */
33
34 #include "includes.h"
35 #include "libcli/ldap/ldap_ndr.h"
36 #include "ldb/include/ldb_errors.h"
37 #include "ldb/include/ldb.h"
38 #include "ldb/include/ldb_private.h"
39 #include "librpc/gen_ndr/misc.h"
40 #include "librpc/gen_ndr/samr.h"
41 #include "libcli/auth/libcli_auth.h"
42 #include "libcli/security/security.h"
43 #include "system/kerberos.h"
44 #include "auth/kerberos/kerberos.h"
45 #include "system/time.h"
46 #include "dsdb/samdb/samdb.h"
47 #include "dsdb/common/flags.h"
48 #include "dsdb/samdb/ldb_modules/password_modules.h"
49 #include "librpc/ndr/libndr.h"
50 #include "librpc/gen_ndr/ndr_drsblobs.h"
51 #include "lib/crypto/crypto.h"
52 #include "param/param.h"
53
54 /* If we have decided there is reason to work on this request, then
55  * setup all the password hash types correctly.
56  *
57  * If the administrator doesn't want the userPassword stored (set in the
58  * domain and per-account policies) then we must strip that out before
59  * we do the first operation.
60  *
61  * Once this is done (which could update anything at all), we
62  * calculate the password hashes.
63  *
64  * This function must not only update the unicodePwd, dBCSPwd and
65  * supplementalCredentials fields, it must also atomicly increment the
66  * msDS-KeyVersionNumber.  We should be in a transaction, so all this
67  * should be quite safe...
68  *
69  * Finally, if the administrator has requested that a password history
70  * be maintained, then this should also be written out.
71  *
72  */
73
74 struct ph_context {
75
76         enum ph_type {PH_ADD, PH_MOD} type;
77         enum ph_step {PH_ADD_SEARCH_DOM, PH_ADD_DO_ADD, PH_MOD_DO_REQ, PH_MOD_SEARCH_SELF, PH_MOD_SEARCH_DOM, PH_MOD_DO_MOD} step;
78
79         struct ldb_module *module;
80         struct ldb_request *orig_req;
81
82         struct ldb_request *dom_req;
83         struct ldb_reply *dom_res;
84
85         struct ldb_request *down_req;
86
87         struct ldb_request *search_req;
88         struct ldb_reply *search_res;
89
90         struct ldb_request *mod_req;
91
92         struct dom_sid *domain_sid;
93 };
94
95 struct domain_data {
96         bool store_cleartext;
97         uint_t pwdProperties;
98         uint_t pwdHistoryLength;
99         char *netbios_domain;
100         char *dns_domain;
101         char *realm;
102 };
103
104 struct setup_password_fields_io {
105         struct ph_context *ac;
106         struct domain_data *domain;
107         struct smb_krb5_context *smb_krb5_context;
108
109         /* infos about the user account */
110         struct {
111                 uint32_t user_account_control;
112                 const char *sAMAccountName;
113                 const char *user_principal_name;
114                 bool is_computer;
115         } u;
116
117         /* new credentials */
118         struct {
119                 const char *cleartext;
120                 struct samr_Password *nt_hash;
121                 struct samr_Password *lm_hash;
122         } n;
123
124         /* old credentials */
125         struct {
126                 uint32_t nt_history_len;
127                 struct samr_Password *nt_history;
128                 uint32_t lm_history_len;
129                 struct samr_Password *lm_history;
130                 const struct ldb_val *supplemental;
131                 struct supplementalCredentialsBlob scb;
132                 uint32_t kvno;
133         } o;
134
135         /* generated credentials */
136         struct {
137                 struct samr_Password *nt_hash;
138                 struct samr_Password *lm_hash;
139                 uint32_t nt_history_len;
140                 struct samr_Password *nt_history;
141                 uint32_t lm_history_len;
142                 struct samr_Password *lm_history;
143                 const char *salt;
144                 DATA_BLOB des_md5;
145                 DATA_BLOB des_crc;
146                 struct ldb_val supplemental;
147                 NTTIME last_set;
148                 uint32_t kvno;
149         } g;
150 };
151
152 static int setup_nt_fields(struct setup_password_fields_io *io)
153 {
154         uint32_t i;
155
156         io->g.nt_hash = io->n.nt_hash;
157
158         if (io->domain->pwdHistoryLength == 0) {
159                 return LDB_SUCCESS;
160         }
161
162         /* We might not have an old NT password */
163         io->g.nt_history = talloc_array(io->ac,
164                                         struct samr_Password,
165                                         io->domain->pwdHistoryLength);
166         if (!io->g.nt_history) {
167                 ldb_oom(io->ac->module->ldb);
168                 return LDB_ERR_OPERATIONS_ERROR;
169         }
170
171         for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.nt_history_len); i++) {
172                 io->g.nt_history[i+1] = io->o.nt_history[i];
173         }
174         io->g.nt_history_len = i + 1;
175
176         if (io->g.nt_hash) {
177                 io->g.nt_history[0] = *io->g.nt_hash;
178         } else {
179                 /* 
180                  * TODO: is this correct?
181                  * the simular behavior is correct for the lm history case
182                  */
183                 E_md4hash("", io->g.nt_history[0].hash);
184         }
185
186         return LDB_SUCCESS;
187 }
188
189 static int setup_lm_fields(struct setup_password_fields_io *io)
190 {
191         uint32_t i;
192
193         io->g.lm_hash = io->n.lm_hash;
194
195         if (io->domain->pwdHistoryLength == 0) {
196                 return LDB_SUCCESS;
197         }
198
199         /* We might not have an old NT password */
200         io->g.lm_history = talloc_array(io->ac,
201                                         struct samr_Password,
202                                         io->domain->pwdHistoryLength);
203         if (!io->g.lm_history) {
204                 ldb_oom(io->ac->module->ldb);
205                 return LDB_ERR_OPERATIONS_ERROR;
206         }
207
208         for (i = 0; i < MIN(io->domain->pwdHistoryLength-1, io->o.lm_history_len); i++) {
209                 io->g.lm_history[i+1] = io->o.lm_history[i];
210         }
211         io->g.lm_history_len = i + 1;
212
213         if (io->g.lm_hash) {
214                 io->g.lm_history[0] = *io->g.lm_hash;
215         } else {
216                 E_deshash("", io->g.lm_history[0].hash);
217         }
218
219         return LDB_SUCCESS;
220 }
221
222 static int setup_kerberos_keys(struct setup_password_fields_io *io)
223 {
224         krb5_error_code krb5_ret;
225         Principal *salt_principal;
226         krb5_salt salt;
227         krb5_keyblock key;
228
229         /* Many, many thanks to lukeh@padl.com for this
230          * algorithm, described in his Nov 10 2004 mail to
231          * samba-technical@samba.org */
232
233         /*
234          * Determine a salting principal
235          */
236         if (io->u.is_computer) {
237                 char *name;
238                 char *saltbody;
239
240                 name = talloc_strdup(io->ac, io->u.sAMAccountName);
241                 if (!name) {
242                         ldb_oom(io->ac->module->ldb);
243                         return LDB_ERR_OPERATIONS_ERROR;
244                 }
245
246                 if (name[strlen(name)-1] == '$') {
247                         name[strlen(name)-1] = '\0';
248                 }
249
250                 saltbody = talloc_asprintf(io->ac, "%s.%s", name, io->domain->dns_domain);
251                 if (!saltbody) {
252                         ldb_oom(io->ac->module->ldb);
253                         return LDB_ERR_OPERATIONS_ERROR;
254                 }
255                 
256                 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
257                                                &salt_principal,
258                                                io->domain->realm, "host",
259                                                saltbody, NULL);
260         } else if (io->u.user_principal_name) {
261                 char *user_principal_name;
262                 char *p;
263
264                 user_principal_name = talloc_strdup(io->ac, io->u.user_principal_name);
265                 if (!user_principal_name) {
266                         ldb_oom(io->ac->module->ldb);
267                         return LDB_ERR_OPERATIONS_ERROR;
268                 }
269
270                 p = strchr(user_principal_name, '@');
271                 if (p) {
272                         p[0] = '\0';
273                 }
274
275                 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
276                                                &salt_principal,
277                                                io->domain->realm, user_principal_name,
278                                                NULL);
279         } else {
280                 krb5_ret = krb5_make_principal(io->smb_krb5_context->krb5_context,
281                                                &salt_principal,
282                                                io->domain->realm, io->u.sAMAccountName,
283                                                NULL);
284         }
285         if (krb5_ret) {
286                 ldb_asprintf_errstring(io->ac->module->ldb,
287                                        "setup_kerberos_keys: "
288                                        "generation of a salting principal failed: %s",
289                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
290                 return LDB_ERR_OPERATIONS_ERROR;
291         }
292
293         /*
294          * create salt from salt_principal
295          */
296         krb5_ret = krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
297                                     salt_principal, &salt);
298         krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
299         if (krb5_ret) {
300                 ldb_asprintf_errstring(io->ac->module->ldb,
301                                        "setup_kerberos_keys: "
302                                        "generation of krb5_salt failed: %s",
303                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
304                 return LDB_ERR_OPERATIONS_ERROR;
305         }
306         /* create a talloc copy */
307         io->g.salt = talloc_strndup(io->ac,
308                                     salt.saltvalue.data,
309                                     salt.saltvalue.length);
310         krb5_free_salt(io->smb_krb5_context->krb5_context, salt);
311         if (!io->g.salt) {
312                 ldb_oom(io->ac->module->ldb);
313                 return LDB_ERR_OPERATIONS_ERROR;
314         }
315         salt.saltvalue.data     = discard_const(io->g.salt);
316         salt.saltvalue.length   = strlen(io->g.salt);
317
318         /*
319          * create ENCTYPE_DES_CBC_MD5 key out of
320          * the salt and the cleartext password
321          */
322         krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
323                                            ENCTYPE_DES_CBC_MD5,
324                                            io->n.cleartext,
325                                            salt,
326                                            &key);
327         if (krb5_ret) {
328                 ldb_asprintf_errstring(io->ac->module->ldb,
329                                        "setup_kerberos_keys: "
330                                        "generation of a des-cbc-md5 key failed: %s",
331                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
332                 return LDB_ERR_OPERATIONS_ERROR;
333         }
334         io->g.des_md5 = data_blob_talloc(io->ac,
335                                          key.keyvalue.data,
336                                          key.keyvalue.length);
337         krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
338         if (!io->g.des_md5.data) {
339                 ldb_oom(io->ac->module->ldb);
340                 return LDB_ERR_OPERATIONS_ERROR;
341         }
342
343         /*
344          * create ENCTYPE_DES_CBC_CRC key out of
345          * the salt and the cleartext password
346          */
347         krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
348                                            ENCTYPE_DES_CBC_CRC,
349                                            io->n.cleartext,
350                                            salt,
351                                            &key);
352         if (krb5_ret) {
353                 ldb_asprintf_errstring(io->ac->module->ldb,
354                                        "setup_kerberos_keys: "
355                                        "generation of a des-cbc-crc key failed: %s",
356                                        smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac));
357                 return LDB_ERR_OPERATIONS_ERROR;
358         }
359         io->g.des_crc = data_blob_talloc(io->ac,
360                                          key.keyvalue.data,
361                                          key.keyvalue.length);
362         krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
363         if (!io->g.des_crc.data) {
364                 ldb_oom(io->ac->module->ldb);
365                 return LDB_ERR_OPERATIONS_ERROR;
366         }
367
368         return LDB_SUCCESS;
369 }
370
371 static int setup_primary_kerberos(struct setup_password_fields_io *io,
372                                   const struct supplementalCredentialsBlob *old_scb,
373                                   struct package_PrimaryKerberosBlob *pkb)
374 {
375         struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
376         struct supplementalCredentialsPackage *old_scp = NULL;
377         struct package_PrimaryKerberosBlob _old_pkb;
378         struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
379         uint32_t i;
380         enum ndr_err_code ndr_err;
381
382         /*
383          * prepare generation of keys
384          *
385          * ENCTYPE_DES_CBC_MD5
386          * ENCTYPE_DES_CBC_CRC
387          */
388         pkb3->salt.string       = io->g.salt;
389         pkb3->num_keys          = 2;
390         pkb3->keys              = talloc_array(io->ac,
391                                                struct package_PrimaryKerberosKey,
392                                                pkb3->num_keys);
393         if (!pkb3->keys) {
394                 ldb_oom(io->ac->module->ldb);
395                 return LDB_ERR_OPERATIONS_ERROR;
396         }
397
398         pkb3->keys[0].keytype   = ENCTYPE_DES_CBC_MD5;
399         pkb3->keys[0].value     = &io->g.des_md5;
400         pkb3->keys[1].keytype   = ENCTYPE_DES_CBC_CRC;
401         pkb3->keys[1].value     = &io->g.des_crc;
402
403         /* initialize the old keys to zero */
404         pkb3->num_old_keys      = 0;
405         pkb3->old_keys          = NULL;
406
407         /* if there're no old keys, then we're done */
408         if (!old_scb) {
409                 return LDB_SUCCESS;
410         }
411
412         for (i=0; i < old_scb->sub.num_packages; i++) {
413                 if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
414                         continue;
415                 }
416
417                 if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
418                         continue;
419                 }
420
421                 old_scp = &old_scb->sub.packages[i];
422                 break;
423         }
424         /* Primary:Kerberos element of supplementalCredentials */
425         if (old_scp) {
426                 DATA_BLOB blob;
427
428                 blob = strhex_to_data_blob(old_scp->data);
429                 if (!blob.data) {
430                         ldb_oom(io->ac->module->ldb);
431                         return LDB_ERR_OPERATIONS_ERROR;
432                 }
433                 talloc_steal(io->ac, blob.data);
434
435                 /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
436                 ndr_err = ndr_pull_struct_blob(&blob, io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), &_old_pkb,
437                                                (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
438                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
439                         NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
440                         ldb_asprintf_errstring(io->ac->module->ldb,
441                                                "setup_primary_kerberos: "
442                                                "failed to pull old package_PrimaryKerberosBlob: %s",
443                                                nt_errstr(status));
444                         return LDB_ERR_OPERATIONS_ERROR;
445                 }
446
447                 if (_old_pkb.version != 3) {
448                         ldb_asprintf_errstring(io->ac->module->ldb,
449                                                "setup_primary_kerberos: "
450                                                "package_PrimaryKerberosBlob version[%u] expected[3]",
451                                                _old_pkb.version);
452                         return LDB_ERR_OPERATIONS_ERROR;
453                 }
454
455                 old_pkb3 = &_old_pkb.ctr.ctr3;
456         }
457
458         /* if we didn't found the old keys we're done */
459         if (!old_pkb3) {
460                 return LDB_SUCCESS;
461         }
462
463         /* fill in the old keys */
464         pkb3->num_old_keys      = old_pkb3->num_keys;
465         pkb3->old_keys          = old_pkb3->keys;
466
467         return LDB_SUCCESS;
468 }
469
470 static int setup_primary_wdigest(struct setup_password_fields_io *io,
471                                  const struct supplementalCredentialsBlob *old_scb,
472                                  struct package_PrimaryWDigestBlob *pdb)
473 {
474         DATA_BLOB sAMAccountName;
475         DATA_BLOB sAMAccountName_l;
476         DATA_BLOB sAMAccountName_u;
477         const char *user_principal_name = io->u.user_principal_name;
478         DATA_BLOB userPrincipalName;
479         DATA_BLOB userPrincipalName_l;
480         DATA_BLOB userPrincipalName_u;
481         DATA_BLOB netbios_domain;
482         DATA_BLOB netbios_domain_l;
483         DATA_BLOB netbios_domain_u;
484         DATA_BLOB dns_domain;
485         DATA_BLOB dns_domain_l;
486         DATA_BLOB dns_domain_u;
487         DATA_BLOB cleartext;
488         DATA_BLOB digest;
489         DATA_BLOB delim;
490         DATA_BLOB backslash;
491         uint8_t i;
492         struct {
493                 DATA_BLOB *user;
494                 DATA_BLOB *realm;
495                 DATA_BLOB *nt4dom;
496         } wdigest[] = {
497         /*
498          * See
499          * http://technet2.microsoft.com/WindowsServer/en/library/717b450c-f4a0-4cc9-86f4-cc0633aae5f91033.mspx?mfr=true
500          * for what precalculated hashes are supposed to be stored...
501          *
502          * I can't reproduce all values which should contain "Digest" as realm,
503          * am I doing something wrong or is w2k3 just broken...?
504          *
505          * W2K3 fills in following for a user:
506          *
507          * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
508          * sAMAccountName: NewUser2Sam
509          * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
510          *
511          * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
512          * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
513          * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
514          * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
515          * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
516          * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
517          * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
518          * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
519          * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
520          * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
521          * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
522          * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
523          * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
524          * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
525          * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
526          * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
527          * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
528          * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
529          * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
530          * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
531          * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
532          * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
533          * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
534          * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
535          * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
536          * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
537          * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
538          * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
539          * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
540          *
541          * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
542          * sAMAccountName: NewUser2Sam
543          *
544          * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
545          * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
546          * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
547          * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
548          * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
549          * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
550          * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
551          * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
552          * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
553          * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
554          * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
555          * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
556          * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
557          * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
558          * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
559          * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
560          * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
561          * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
562          * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
563          * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
564          * 31dc704d3640335b2123d4ee28aa1f11 => ???M1   changes with NewUser2Sam => NewUser1Sam
565          * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
566          * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
567          * 569b4533f2d9e580211dd040e5e360a8 => ???M2   changes with NewUser2Princ => NewUser1Princ
568          * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
569          * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
570          * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
571          * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
572          * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
573          */
574
575         /*
576          * sAMAccountName, netbios_domain
577          */
578                 {
579                 .user   = &sAMAccountName,
580                 .realm  = &netbios_domain,
581                 },
582                 {
583                 .user   = &sAMAccountName_l,
584                 .realm  = &netbios_domain_l,
585                 },
586                 {
587                 .user   = &sAMAccountName_u,
588                 .realm  = &netbios_domain_u,
589                 },
590                 {
591                 .user   = &sAMAccountName,
592                 .realm  = &netbios_domain_u,
593                 },
594                 {
595                 .user   = &sAMAccountName,
596                 .realm  = &netbios_domain_l,
597                 },
598                 {
599                 .user   = &sAMAccountName_u,
600                 .realm  = &netbios_domain_l,
601                 },
602                 {
603                 .user   = &sAMAccountName_l,
604                 .realm  = &netbios_domain_u,
605                 },
606         /* 
607          * sAMAccountName, dns_domain
608          */
609                 {
610                 .user   = &sAMAccountName,
611                 .realm  = &dns_domain,
612                 },
613                 {
614                 .user   = &sAMAccountName_l,
615                 .realm  = &dns_domain_l,
616                 },
617                 {
618                 .user   = &sAMAccountName_u,
619                 .realm  = &dns_domain_u,
620                 },
621                 {
622                 .user   = &sAMAccountName,
623                 .realm  = &dns_domain_u,
624                 },
625                 {
626                 .user   = &sAMAccountName,
627                 .realm  = &dns_domain_l,
628                 },
629                 {
630                 .user   = &sAMAccountName_u,
631                 .realm  = &dns_domain_l,
632                 },
633                 {
634                 .user   = &sAMAccountName_l,
635                 .realm  = &dns_domain_u,
636                 },
637         /* 
638          * userPrincipalName, no realm
639          */
640                 {
641                 .user   = &userPrincipalName,
642                 },
643                 {
644                 /* 
645                  * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
646                  *       the fallback to the sAMAccountName based userPrincipalName is correct
647                  */
648                 .user   = &userPrincipalName_l,
649                 },
650                 {
651                 .user   = &userPrincipalName_u,
652                 },
653         /* 
654          * nt4dom\sAMAccountName, no realm
655          */
656                 {
657                 .user   = &sAMAccountName,
658                 .nt4dom = &netbios_domain
659                 },
660                 {
661                 .user   = &sAMAccountName_l,
662                 .nt4dom = &netbios_domain_l
663                 },
664                 {
665                 .user   = &sAMAccountName_u,
666                 .nt4dom = &netbios_domain_u
667                 },
668
669         /*
670          * the following ones are guessed depending on the technet2 article
671          * but not reproducable on a w2k3 server
672          */
673         /* sAMAccountName with "Digest" realm */
674                 {
675                 .user   = &sAMAccountName,
676                 .realm  = &digest
677                 },
678                 {
679                 .user   = &sAMAccountName_l,
680                 .realm  = &digest
681                 },
682                 {
683                 .user   = &sAMAccountName_u,
684                 .realm  = &digest
685                 },
686         /* userPrincipalName with "Digest" realm */
687                 {
688                 .user   = &userPrincipalName,
689                 .realm  = &digest
690                 },
691                 {
692                 .user   = &userPrincipalName_l,
693                 .realm  = &digest
694                 },
695                 {
696                 .user   = &userPrincipalName_u,
697                 .realm  = &digest
698                 },
699         /* nt4dom\\sAMAccountName with "Digest" realm */
700                 {
701                 .user   = &sAMAccountName,
702                 .nt4dom = &netbios_domain,
703                 .realm  = &digest
704                 },
705                 {
706                 .user   = &sAMAccountName_l,
707                 .nt4dom = &netbios_domain_l,
708                 .realm  = &digest
709                 },
710                 {
711                 .user   = &sAMAccountName_u,
712                 .nt4dom = &netbios_domain_u,
713                 .realm  = &digest
714                 },
715         };
716
717         /* prepare DATA_BLOB's used in the combinations array */
718         sAMAccountName          = data_blob_string_const(io->u.sAMAccountName);
719         sAMAccountName_l        = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
720         if (!sAMAccountName_l.data) {
721                 ldb_oom(io->ac->module->ldb);
722                 return LDB_ERR_OPERATIONS_ERROR;
723         }
724         sAMAccountName_u        = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
725         if (!sAMAccountName_u.data) {
726                 ldb_oom(io->ac->module->ldb);
727                 return LDB_ERR_OPERATIONS_ERROR;
728         }
729
730         /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
731         if (!user_principal_name) {
732                 user_principal_name = talloc_asprintf(io->ac, "%s@%s",
733                                                       io->u.sAMAccountName,
734                                                       io->domain->dns_domain);
735                 if (!user_principal_name) {
736                         ldb_oom(io->ac->module->ldb);
737                         return LDB_ERR_OPERATIONS_ERROR;
738                 }       
739         }
740         userPrincipalName       = data_blob_string_const(user_principal_name);
741         userPrincipalName_l     = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
742         if (!userPrincipalName_l.data) {
743                 ldb_oom(io->ac->module->ldb);
744                 return LDB_ERR_OPERATIONS_ERROR;
745         }
746         userPrincipalName_u     = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
747         if (!userPrincipalName_u.data) {
748                 ldb_oom(io->ac->module->ldb);
749                 return LDB_ERR_OPERATIONS_ERROR;
750         }
751
752         netbios_domain          = data_blob_string_const(io->domain->netbios_domain);
753         netbios_domain_l        = data_blob_string_const(strlower_talloc(io->ac, io->domain->netbios_domain));
754         if (!netbios_domain_l.data) {
755                 ldb_oom(io->ac->module->ldb);
756                 return LDB_ERR_OPERATIONS_ERROR;
757         }
758         netbios_domain_u        = data_blob_string_const(strupper_talloc(io->ac, io->domain->netbios_domain));
759         if (!netbios_domain_u.data) {
760                 ldb_oom(io->ac->module->ldb);
761                 return LDB_ERR_OPERATIONS_ERROR;
762         }
763
764         dns_domain              = data_blob_string_const(io->domain->dns_domain);
765         dns_domain_l            = data_blob_string_const(io->domain->dns_domain);
766         dns_domain_u            = data_blob_string_const(io->domain->realm);
767
768         cleartext               = data_blob_string_const(io->n.cleartext);
769
770         digest                  = data_blob_string_const("Digest");
771
772         delim                   = data_blob_string_const(":");
773         backslash               = data_blob_string_const("\\");
774
775         pdb->num_hashes = ARRAY_SIZE(wdigest);
776         pdb->hashes     = talloc_array(io->ac, struct package_PrimaryWDigestHash, pdb->num_hashes);
777         if (!pdb->hashes) {
778                 ldb_oom(io->ac->module->ldb);
779                 return LDB_ERR_OPERATIONS_ERROR;
780         }
781
782         for (i=0; i < ARRAY_SIZE(wdigest); i++) {
783                 struct MD5Context md5;
784                 MD5Init(&md5);
785                 if (wdigest[i].nt4dom) {
786                         MD5Update(&md5, wdigest[i].nt4dom->data, wdigest[i].nt4dom->length);
787                         MD5Update(&md5, backslash.data, backslash.length);
788                 }
789                 MD5Update(&md5, wdigest[i].user->data, wdigest[i].user->length);
790                 MD5Update(&md5, delim.data, delim.length);
791                 if (wdigest[i].realm) {
792                         MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
793                 }
794                 MD5Update(&md5, delim.data, delim.length);
795                 MD5Update(&md5, cleartext.data, cleartext.length);
796                 MD5Final(pdb->hashes[i].hash, &md5);
797         }
798
799         return LDB_SUCCESS;
800 }
801
802 static int setup_supplemental_field(struct setup_password_fields_io *io)
803 {
804         struct supplementalCredentialsBlob scb;
805         struct supplementalCredentialsBlob _old_scb;
806         struct supplementalCredentialsBlob *old_scb = NULL;
807         /* Packages + (Kerberos, WDigest and CLEARTEXT) */
808         uint32_t num_names = 0;
809         const char *names[1+3];
810         uint32_t num_packages = 0;
811         struct supplementalCredentialsPackage packages[1+3];
812         /* Packages */
813         struct supplementalCredentialsPackage *pp = NULL;
814         struct package_PackagesBlob pb;
815         DATA_BLOB pb_blob;
816         char *pb_hexstr;
817         /* Primary:Kerberos */
818         const char **nk = NULL;
819         struct supplementalCredentialsPackage *pk = NULL;
820         struct package_PrimaryKerberosBlob pkb;
821         DATA_BLOB pkb_blob;
822         char *pkb_hexstr;
823         /* Primary:WDigest */
824         const char **nd = NULL;
825         struct supplementalCredentialsPackage *pd = NULL;
826         struct package_PrimaryWDigestBlob pdb;
827         DATA_BLOB pdb_blob;
828         char *pdb_hexstr;
829         /* Primary:CLEARTEXT */
830         const char **nc = NULL;
831         struct supplementalCredentialsPackage *pc = NULL;
832         struct package_PrimaryCLEARTEXTBlob pcb;
833         DATA_BLOB pcb_blob;
834         char *pcb_hexstr;
835         int ret;
836         enum ndr_err_code ndr_err;
837         uint8_t zero16[16];
838         bool do_cleartext = false;
839
840         ZERO_STRUCT(zero16);
841         ZERO_STRUCT(names);
842
843         if (!io->n.cleartext) {
844                 /* 
845                  * when we don't have a cleartext password
846                  * we can't setup a supplementalCredential value
847                  */
848                 return LDB_SUCCESS;
849         }
850
851         /* if there's an old supplementaCredentials blob then parse it */
852         if (io->o.supplemental) {
853                 ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
854                                                    lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
855                                                    &_old_scb,
856                                                    (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
857                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
858                         NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
859                         ldb_asprintf_errstring(io->ac->module->ldb,
860                                                "setup_supplemental_field: "
861                                                "failed to pull old supplementalCredentialsBlob: %s",
862                                                nt_errstr(status));
863                         return LDB_ERR_OPERATIONS_ERROR;
864                 }
865
866                 if (_old_scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
867                         old_scb = &_old_scb;
868                 } else {
869                         ldb_debug(io->ac->module->ldb, LDB_DEBUG_ERROR,
870                                                "setup_supplemental_field: "
871                                                "supplementalCredentialsBlob signature[0x%04X] expected[0x%04X]",
872                                                _old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
873                 }
874         }
875
876         if (io->domain->store_cleartext &&
877             (io->u.user_account_control & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
878                 do_cleartext = true;
879         }
880
881         /*
882          * The ordering is this
883          *
884          * Primary:Kerberos
885          * Primary:WDigest
886          * Primary:CLEARTEXT (optional)
887          *
888          * And the 'Packages' package is insert before the last
889          * other package.
890          */
891
892         /* Primary:Kerberos */
893         nk = &names[num_names++];
894         pk = &packages[num_packages++];
895
896         if (!do_cleartext) {
897                 /* Packages */
898                 pp = &packages[num_packages++];
899         }
900
901         /* Primary:WDigest */
902         nd = &names[num_names++];
903         pd = &packages[num_packages++];
904
905         if (do_cleartext) {
906                 /* Packages */
907                 pp = &packages[num_packages++];
908
909                 /* Primary:CLEARTEXT */
910                 nc = &names[num_names++];
911                 pc = &packages[num_packages++];
912         }
913
914         /*
915          * setup 'Primary:Kerberos' element
916          */
917         *nk = "Kerberos";
918
919         ret = setup_primary_kerberos(io, old_scb, &pkb);
920         if (ret != LDB_SUCCESS) {
921                 return ret;
922         }
923
924         ndr_err = ndr_push_struct_blob(&pkb_blob, io->ac, 
925                                        lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
926                                        &pkb,
927                                        (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
928         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
929                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
930                 ldb_asprintf_errstring(io->ac->module->ldb,
931                                        "setup_supplemental_field: "
932                                        "failed to push package_PrimaryKerberosBlob: %s",
933                                        nt_errstr(status));
934                 return LDB_ERR_OPERATIONS_ERROR;
935         }
936         pkb_hexstr = data_blob_hex_string(io->ac, &pkb_blob);
937         if (!pkb_hexstr) {
938                 ldb_oom(io->ac->module->ldb);
939                 return LDB_ERR_OPERATIONS_ERROR;
940         }
941         pk->name        = "Primary:Kerberos";
942         pk->reserved    = 1;
943         pk->data        = pkb_hexstr;
944
945         /*
946          * setup 'Primary:WDigest' element
947          */
948         *nd = "WDigest";
949
950         ret = setup_primary_wdigest(io, old_scb, &pdb);
951         if (ret != LDB_SUCCESS) {
952                 return ret;
953         }
954
955         ndr_err = ndr_push_struct_blob(&pdb_blob, io->ac, 
956                                        lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
957                                        &pdb,
958                                        (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
959         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
960                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
961                 ldb_asprintf_errstring(io->ac->module->ldb,
962                                        "setup_supplemental_field: "
963                                        "failed to push package_PrimaryWDigestBlob: %s",
964                                        nt_errstr(status));
965                 return LDB_ERR_OPERATIONS_ERROR;
966         }
967         pdb_hexstr = data_blob_hex_string(io->ac, &pdb_blob);
968         if (!pdb_hexstr) {
969                 ldb_oom(io->ac->module->ldb);
970                 return LDB_ERR_OPERATIONS_ERROR;
971         }
972         pd->name        = "Primary:WDigest";
973         pd->reserved    = 1;
974         pd->data        = pdb_hexstr;
975
976         /*
977          * setup 'Primary:CLEARTEXT' element
978          */
979         if (pc) {
980                 *nc             = "CLEARTEXT";
981
982                 pcb.cleartext   = io->n.cleartext;
983
984                 ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac, 
985                                                lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
986                                                &pcb,
987                                                (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
988                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
989                         NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
990                         ldb_asprintf_errstring(io->ac->module->ldb,
991                                                "setup_supplemental_field: "
992                                                "failed to push package_PrimaryCLEARTEXTBlob: %s",
993                                                nt_errstr(status));
994                         return LDB_ERR_OPERATIONS_ERROR;
995                 }
996                 pcb_hexstr = data_blob_hex_string(io->ac, &pcb_blob);
997                 if (!pcb_hexstr) {
998                         ldb_oom(io->ac->module->ldb);
999                         return LDB_ERR_OPERATIONS_ERROR;
1000                 }
1001                 pc->name        = "Primary:CLEARTEXT";
1002                 pc->reserved    = 1;
1003                 pc->data        = pcb_hexstr;
1004         }
1005
1006         /*
1007          * setup 'Packages' element
1008          */
1009         pb.names = names;
1010         ndr_err = ndr_push_struct_blob(&pb_blob, io->ac, 
1011                                        lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), 
1012                                        &pb,
1013                                        (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
1014         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1015                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1016                 ldb_asprintf_errstring(io->ac->module->ldb,
1017                                        "setup_supplemental_field: "
1018                                        "failed to push package_PackagesBlob: %s",
1019                                        nt_errstr(status));
1020                 return LDB_ERR_OPERATIONS_ERROR;
1021         }
1022         pb_hexstr = data_blob_hex_string(io->ac, &pb_blob);
1023         if (!pb_hexstr) {
1024                 ldb_oom(io->ac->module->ldb);
1025                 return LDB_ERR_OPERATIONS_ERROR;
1026         }
1027         pp->name        = "Packages";
1028         pp->reserved    = 2;
1029         pp->data        = pb_hexstr;
1030
1031         /*
1032          * setup 'supplementalCredentials' value
1033          */
1034         ZERO_STRUCT(scb);
1035         scb.sub.num_packages    = num_packages;
1036         scb.sub.packages        = packages;
1037
1038         ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac, 
1039                                        lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
1040                                        &scb,
1041                                        (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
1042         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1043                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1044                 ldb_asprintf_errstring(io->ac->module->ldb,
1045                                        "setup_supplemental_field: "
1046                                        "failed to push supplementalCredentialsBlob: %s",
1047                                        nt_errstr(status));
1048                 return LDB_ERR_OPERATIONS_ERROR;
1049         }
1050
1051         return LDB_SUCCESS;
1052 }
1053
1054 static int setup_last_set_field(struct setup_password_fields_io *io)
1055 {
1056         /* set it as now */
1057         unix_to_nt_time(&io->g.last_set, time(NULL));
1058
1059         return LDB_SUCCESS;
1060 }
1061
1062 static int setup_kvno_field(struct setup_password_fields_io *io)
1063 {
1064         /* increment by one */
1065         io->g.kvno = io->o.kvno + 1;
1066
1067         return LDB_SUCCESS;
1068 }
1069
1070 static int setup_password_fields(struct setup_password_fields_io *io)
1071 {
1072         bool ok;
1073         int ret;
1074
1075         /*
1076          * refuse the change if someone want to change the cleartext
1077          * and supply his own hashes at the same time...
1078          */
1079         if (io->n.cleartext && (io->n.nt_hash || io->n.lm_hash)) {
1080                 ldb_asprintf_errstring(io->ac->module->ldb,
1081                                        "setup_password_fields: "
1082                                        "it's only allowed to set the cleartext password or the password hashes");
1083                 return LDB_ERR_UNWILLING_TO_PERFORM;
1084         }
1085
1086         if (io->n.cleartext) {
1087                 struct samr_Password *hash;
1088
1089                 hash = talloc(io->ac, struct samr_Password);
1090                 if (!hash) {
1091                         ldb_oom(io->ac->module->ldb);
1092                         return LDB_ERR_OPERATIONS_ERROR;
1093                 }
1094
1095                 /* compute the new nt hash */
1096                 ok = E_md4hash(io->n.cleartext, hash->hash);
1097                 if (ok) {
1098                         io->n.nt_hash = hash;
1099                 } else {
1100                         ldb_asprintf_errstring(io->ac->module->ldb,
1101                                                "setup_password_fields: "
1102                                                "failed to generate nthash from cleartext password");
1103                         return LDB_ERR_OPERATIONS_ERROR;
1104                 }
1105         }
1106
1107         if (io->n.cleartext) {
1108                 struct samr_Password *hash;
1109
1110                 hash = talloc(io->ac, struct samr_Password);
1111                 if (!hash) {
1112                         ldb_oom(io->ac->module->ldb);
1113                         return LDB_ERR_OPERATIONS_ERROR;
1114                 }
1115
1116                 /* compute the new lm hash */
1117                 ok = E_deshash(io->n.cleartext, hash->hash);
1118                 if (ok) {
1119                         io->n.lm_hash = hash;
1120                 } else {
1121                         talloc_free(hash->hash);
1122                 }
1123         }
1124
1125         if (io->n.cleartext) {
1126                 ret = setup_kerberos_keys(io);
1127                 if (ret != 0) {
1128                         return ret;
1129                 }
1130         }
1131
1132         ret = setup_nt_fields(io);
1133         if (ret != 0) {
1134                 return ret;
1135         }
1136
1137         ret = setup_lm_fields(io);
1138         if (ret != 0) {
1139                 return ret;
1140         }
1141
1142         ret = setup_supplemental_field(io);
1143         if (ret != 0) {
1144                 return ret;
1145         }
1146
1147         ret = setup_last_set_field(io);
1148         if (ret != 0) {
1149                 return ret;
1150         }
1151
1152         ret = setup_kvno_field(io);
1153         if (ret != 0) {
1154                 return ret;
1155         }
1156
1157         return LDB_SUCCESS;
1158 }
1159
1160 static struct ldb_handle *ph_init_handle(struct ldb_request *req, struct ldb_module *module, enum ph_type type)
1161 {
1162         struct ph_context *ac;
1163         struct ldb_handle *h;
1164
1165         h = talloc_zero(req, struct ldb_handle);
1166         if (h == NULL) {
1167                 ldb_set_errstring(module->ldb, "Out of Memory");
1168                 return NULL;
1169         }
1170
1171         h->module = module;
1172
1173         ac = talloc_zero(h, struct ph_context);
1174         if (ac == NULL) {
1175                 ldb_set_errstring(module->ldb, "Out of Memory");
1176                 talloc_free(h);
1177                 return NULL;
1178         }
1179
1180         h->private_data = (void *)ac;
1181
1182         h->state = LDB_ASYNC_INIT;
1183         h->status = LDB_SUCCESS;
1184
1185         ac->type = type;
1186         ac->module = module;
1187         ac->orig_req = req;
1188
1189         return h;
1190 }
1191
1192 static int get_domain_data_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
1193 {
1194         struct ph_context *ac;
1195
1196         ac = talloc_get_type(context, struct ph_context);
1197
1198         /* we are interested only in the single reply (base search) we receive here */
1199         if (ares->type == LDB_REPLY_ENTRY) {
1200                 if (ac->dom_res != NULL) {
1201                         ldb_set_errstring(ldb, "Too many results");
1202                         talloc_free(ares);
1203                         return LDB_ERR_OPERATIONS_ERROR;
1204                 }
1205                 ac->dom_res = talloc_steal(ac, ares);
1206         } else {
1207                 talloc_free(ares);
1208         }
1209
1210         return LDB_SUCCESS;
1211 }
1212
1213 static int build_domain_data_request(struct ph_context *ac)
1214 {
1215         /* attrs[] is returned from this function in
1216            ac->dom_req->op.search.attrs, so it must be static, as
1217            otherwise the compiler can put it on the stack */
1218         static const char * const attrs[] = { "pwdProperties", "pwdHistoryLength", NULL };
1219         char *filter;
1220
1221         ac->dom_req = talloc_zero(ac, struct ldb_request);
1222         if (ac->dom_req == NULL) {
1223                 ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
1224                 return LDB_ERR_OPERATIONS_ERROR;
1225         }
1226         ac->dom_req->operation = LDB_SEARCH;
1227         ac->dom_req->op.search.base = ldb_get_default_basedn(ac->module->ldb);
1228         ac->dom_req->op.search.scope = LDB_SCOPE_SUBTREE;
1229
1230         filter = talloc_asprintf(ac->dom_req,
1231                                  "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))", 
1232                                  ldap_encode_ndr_dom_sid(ac->dom_req, ac->domain_sid));
1233         if (filter == NULL) {
1234                 ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
1235                 talloc_free(ac->dom_req);
1236                 return LDB_ERR_OPERATIONS_ERROR;
1237         }
1238
1239         ac->dom_req->op.search.tree = ldb_parse_tree(ac->dom_req, filter);
1240         if (ac->dom_req->op.search.tree == NULL) {
1241                 ldb_set_errstring(ac->module->ldb, "Invalid search filter");
1242                 talloc_free(ac->dom_req);
1243                 return LDB_ERR_OPERATIONS_ERROR;
1244         }
1245         ac->dom_req->op.search.attrs = attrs;
1246         ac->dom_req->controls = NULL;
1247         ac->dom_req->context = ac;
1248         ac->dom_req->callback = get_domain_data_callback;
1249         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->dom_req);
1250
1251         return LDB_SUCCESS;
1252 }
1253
1254 static struct domain_data *get_domain_data(struct ldb_module *module, void *ctx, struct ldb_reply *res)
1255 {
1256         struct domain_data *data;
1257         const char *tmp;
1258         struct ph_context *ac;
1259         char *p;
1260
1261         ac = talloc_get_type(ctx, struct ph_context);
1262
1263         data = talloc_zero(ac, struct domain_data);
1264         if (data == NULL) {
1265                 return NULL;
1266         }
1267
1268         if (res == NULL) {
1269                 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Could not find this user's domain: %s!\n", dom_sid_string(data, ac->domain_sid));
1270                 talloc_free(data);
1271                 return NULL;
1272         }
1273
1274         data->pwdProperties= samdb_result_uint(res->message, "pwdProperties", 0);
1275         data->store_cleartext = data->pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
1276         data->pwdHistoryLength = samdb_result_uint(res->message, "pwdHistoryLength", 0);
1277
1278         /* For a domain DN, this puts things in dotted notation */
1279         /* For builtin domains, this will give details for the host,
1280          * but that doesn't really matter, as it's just used for salt
1281          * and kerberos principals, which don't exist here */
1282
1283         tmp = ldb_dn_canonical_string(ctx, res->message->dn);
1284         if (!tmp) {
1285                 return NULL;
1286         }
1287         
1288         /* But it puts a trailing (or just before 'builtin') / on things, so kill that */
1289         p = strchr(tmp, '/');
1290         if (p) {
1291                 p[0] = '\0';
1292         }
1293
1294         if (tmp != NULL) {
1295                 data->dns_domain = strlower_talloc(data, tmp);
1296                 if (data->dns_domain == NULL) {
1297                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of memory!\n");
1298                         return NULL;
1299                 }
1300                 data->realm = strupper_talloc(data, tmp);
1301                 if (data->realm == NULL) {
1302                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of memory!\n");
1303                         return NULL;
1304                 }
1305                 p = strchr(tmp, '.');
1306                 if (p) {
1307                         p[0] = '\0';
1308                 }
1309                 data->netbios_domain = strupper_talloc(data, tmp);
1310                 if (data->netbios_domain == NULL) {
1311                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of memory!\n");
1312                         return NULL;
1313                 }
1314         }
1315
1316         return data;
1317 }
1318
1319 static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
1320 {
1321         struct ldb_handle *h;
1322         struct ph_context *ac;
1323         struct ldb_message_element *sambaAttr;
1324         struct ldb_message_element *ntAttr;
1325         struct ldb_message_element *lmAttr;
1326         int ret;
1327
1328         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
1329
1330         if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
1331                 return ldb_next_request(module, req);
1332         }
1333
1334         /* If the caller is manipulating the local passwords directly, let them pass */
1335         if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
1336                                 req->op.add.message->dn) == 0) {
1337                 return ldb_next_request(module, req);
1338         }
1339
1340         /* nobody must touch this fields */
1341         if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1342                 return LDB_ERR_UNWILLING_TO_PERFORM;
1343         }
1344         if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1345                 return LDB_ERR_UNWILLING_TO_PERFORM;
1346         }
1347         if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1348                 return LDB_ERR_UNWILLING_TO_PERFORM;
1349         }
1350
1351         /* If no part of this ADD touches the userPassword, or the NT
1352          * or LM hashes, then we don't need to make any changes.  */
1353
1354         sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1355         ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1356         lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1357
1358         if ((!sambaAttr) && (!ntAttr) && (!lmAttr)) {
1359                 return ldb_next_request(module, req);
1360         }
1361
1362         /* if it is not an entry of type person its an error */
1363         /* TODO: remove this when userPassword will be in schema */
1364         if (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "person")) {
1365                 ldb_set_errstring(module->ldb, "Cannot set a password on entry that does not have objectClass 'person'");
1366                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1367         }
1368
1369         /* check userPassword is single valued here */
1370         /* TODO: remove this when userPassword will be single valued in schema */
1371         if (sambaAttr && sambaAttr->num_values > 1) {
1372                 ldb_set_errstring(module->ldb, "mupltiple values for userPassword not allowed!\n");
1373                 return LDB_ERR_CONSTRAINT_VIOLATION;
1374         }
1375
1376         if (ntAttr && (ntAttr->num_values > 1)) {
1377                 ldb_set_errstring(module->ldb, "mupltiple values for unicodePwd not allowed!\n");
1378                 return LDB_ERR_CONSTRAINT_VIOLATION;
1379         }
1380         if (lmAttr && (lmAttr->num_values > 1)) {
1381                 ldb_set_errstring(module->ldb, "mupltiple values for dBCSPwd not allowed!\n");
1382                 return LDB_ERR_CONSTRAINT_VIOLATION;
1383         }
1384
1385         if (sambaAttr && sambaAttr->num_values == 0) {
1386                 ldb_set_errstring(module->ldb, "userPassword must have a value!\n");
1387                 return LDB_ERR_CONSTRAINT_VIOLATION;
1388         }
1389
1390         if (ntAttr && (ntAttr->num_values == 0)) {
1391                 ldb_set_errstring(module->ldb, "unicodePwd must have a value!\n");
1392                 return LDB_ERR_CONSTRAINT_VIOLATION;
1393         }
1394         if (lmAttr && (lmAttr->num_values == 0)) {
1395                 ldb_set_errstring(module->ldb, "dBCSPwd must have a value!\n");
1396                 return LDB_ERR_CONSTRAINT_VIOLATION;
1397         }
1398
1399         h = ph_init_handle(req, module, PH_ADD);
1400         if (!h) {
1401                 return LDB_ERR_OPERATIONS_ERROR;
1402         }
1403         ac = talloc_get_type(h->private_data, struct ph_context);
1404
1405         /* get user domain data */
1406         ac->domain_sid = samdb_result_sid_prefix(ac, req->op.add.message, "objectSid");
1407         if (ac->domain_sid == NULL) {
1408                 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "can't handle entry with missing objectSid!\n");
1409                 return LDB_ERR_OPERATIONS_ERROR;
1410         }
1411
1412         ret = build_domain_data_request(ac);
1413         if (ret != LDB_SUCCESS) {
1414                 return ret;
1415         }
1416
1417         ac->step = PH_ADD_SEARCH_DOM;
1418
1419         req->handle = h;
1420
1421         return ldb_next_request(module, ac->dom_req);
1422 }
1423
1424 static int password_hash_add_do_add(struct ldb_handle *h) {
1425
1426         struct ph_context *ac;
1427         struct domain_data *domain;
1428         struct smb_krb5_context *smb_krb5_context;
1429         struct ldb_message *msg;
1430         struct setup_password_fields_io io;
1431         int ret;
1432
1433         ac = talloc_get_type(h->private_data, struct ph_context);
1434
1435         domain = get_domain_data(ac->module, ac, ac->dom_res);
1436         if (domain == NULL) {
1437                 return LDB_ERR_OPERATIONS_ERROR;
1438         }
1439
1440         ac->down_req = talloc(ac, struct ldb_request);
1441         if (ac->down_req == NULL) {
1442                 return LDB_ERR_OPERATIONS_ERROR;
1443         }
1444
1445         *(ac->down_req) = *(ac->orig_req);
1446         ac->down_req->op.add.message = msg = ldb_msg_copy_shallow(ac->down_req, ac->orig_req->op.add.message);
1447         if (ac->down_req->op.add.message == NULL) {
1448                 return LDB_ERR_OPERATIONS_ERROR;
1449         }
1450
1451         /* Some operations below require kerberos contexts */
1452         if (smb_krb5_init_context(ac->down_req, 
1453                                   ldb_get_opaque(h->module->ldb, "EventContext"), 
1454                                   (struct loadparm_context *)ldb_get_opaque(h->module->ldb, "loadparm"), 
1455                                   &smb_krb5_context) != 0) {
1456                 return LDB_ERR_OPERATIONS_ERROR;
1457         }
1458
1459         ZERO_STRUCT(io);
1460         io.ac                           = ac;
1461         io.domain                       = domain;
1462         io.smb_krb5_context             = smb_krb5_context;
1463
1464         io.u.user_account_control       = samdb_result_uint(msg, "userAccountControl", 0);
1465         io.u.sAMAccountName             = samdb_result_string(msg, "samAccountName", NULL);
1466         io.u.user_principal_name        = samdb_result_string(msg, "userPrincipalName", NULL);
1467         io.u.is_computer                = ldb_msg_check_string_attribute(msg, "objectClass", "computer");
1468
1469         io.n.cleartext                  = samdb_result_string(msg, "userPassword", NULL);
1470         io.n.nt_hash                    = samdb_result_hash(io.ac, msg, "unicodePwd");
1471         io.n.lm_hash                    = samdb_result_hash(io.ac, msg, "dBCSPwd");
1472
1473         /* remove attributes */
1474         if (io.n.cleartext) ldb_msg_remove_attr(msg, "userPassword");
1475         if (io.n.nt_hash) ldb_msg_remove_attr(msg, "unicodePwd");
1476         if (io.n.lm_hash) ldb_msg_remove_attr(msg, "dBCSPwd");
1477         ldb_msg_remove_attr(msg, "pwdLastSet");
1478         io.o.kvno = samdb_result_uint(msg, "msDs-KeyVersionNumber", 1) - 1;
1479         ldb_msg_remove_attr(msg, "msDs-KeyVersionNumber");
1480
1481         ret = setup_password_fields(&io);
1482         if (ret != LDB_SUCCESS) {
1483                 return ret;
1484         }
1485
1486         if (io.g.nt_hash) {
1487                 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
1488                                          "unicodePwd", io.g.nt_hash);
1489                 if (ret != LDB_SUCCESS) {
1490                         return ret;
1491                 }
1492         }
1493         if (io.g.lm_hash) {
1494                 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
1495                                          "dBCSPwd", io.g.lm_hash);
1496                 if (ret != LDB_SUCCESS) {
1497                         return ret;
1498                 }
1499         }
1500         if (io.g.nt_history_len > 0) {
1501                 ret = samdb_msg_add_hashes(ac, msg,
1502                                            "ntPwdHistory",
1503                                            io.g.nt_history,
1504                                            io.g.nt_history_len);
1505                 if (ret != LDB_SUCCESS) {
1506                         return ret;
1507                 }
1508         }
1509         if (io.g.lm_history_len > 0) {
1510                 ret = samdb_msg_add_hashes(ac, msg,
1511                                            "lmPwdHistory",
1512                                            io.g.lm_history,
1513                                            io.g.lm_history_len);
1514                 if (ret != LDB_SUCCESS) {
1515                         return ret;
1516                 }
1517         }
1518         if (io.g.supplemental.length > 0) {
1519                 ret = ldb_msg_add_value(msg, "supplementalCredentials",
1520                                         &io.g.supplemental, NULL);
1521                 if (ret != LDB_SUCCESS) {
1522                         return ret;
1523                 }
1524         }
1525         ret = samdb_msg_add_uint64(ac->module->ldb, ac, msg,
1526                                    "pwdLastSet",
1527                                    io.g.last_set);
1528         if (ret != LDB_SUCCESS) {
1529                 return ret;
1530         }
1531         ret = samdb_msg_add_uint(ac->module->ldb, ac, msg,
1532                                  "msDs-KeyVersionNumber",
1533                                  io.g.kvno);
1534         if (ret != LDB_SUCCESS) {
1535                 return ret;
1536         }
1537
1538         h->state = LDB_ASYNC_INIT;
1539         h->status = LDB_SUCCESS;
1540
1541         ac->step = PH_ADD_DO_ADD;
1542
1543         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->down_req);
1544
1545         /* perform the operation */
1546         return ldb_next_request(ac->module, ac->down_req);
1547 }
1548
1549 static int password_hash_mod_search_self(struct ldb_handle *h);
1550
1551 static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
1552 {
1553         struct ldb_handle *h;
1554         struct ph_context *ac;
1555         struct ldb_message_element *sambaAttr;
1556         struct ldb_message_element *ntAttr;
1557         struct ldb_message_element *lmAttr;
1558         struct ldb_message *msg;
1559
1560         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
1561
1562         if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1563                 return ldb_next_request(module, req);
1564         }
1565         
1566         /* If the caller is manipulating the local passwords directly, let them pass */
1567         if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
1568                                 req->op.mod.message->dn) == 0) {
1569                 return ldb_next_request(module, req);
1570         }
1571
1572         /* nobody must touch password Histories */
1573         if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
1574                 return LDB_ERR_UNWILLING_TO_PERFORM;
1575         }
1576         if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) {
1577                 return LDB_ERR_UNWILLING_TO_PERFORM;
1578         }
1579         if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) {
1580                 return LDB_ERR_UNWILLING_TO_PERFORM;
1581         }
1582
1583         sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
1584         ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
1585         lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1586
1587         /* If no part of this touches the userPassword OR unicodePwd and/or dBCSPwd, then we don't
1588          * need to make any changes.  For password changes/set there should
1589          * be a 'delete' or a 'modify' on this attribute. */
1590         if ((!sambaAttr) && (!ntAttr) && (!lmAttr)) {
1591                 return ldb_next_request(module, req);
1592         }
1593
1594         /* check passwords are single valued here */
1595         /* TODO: remove this when passwords will be single valued in schema */
1596         if (sambaAttr && (sambaAttr->num_values > 1)) {
1597                 return LDB_ERR_CONSTRAINT_VIOLATION;
1598         }
1599         if (ntAttr && (ntAttr->num_values > 1)) {
1600                 return LDB_ERR_CONSTRAINT_VIOLATION;
1601         }
1602         if (lmAttr && (lmAttr->num_values > 1)) {
1603                 return LDB_ERR_CONSTRAINT_VIOLATION;
1604         }
1605
1606         h = ph_init_handle(req, module, PH_MOD);
1607         if (!h) {
1608                 return LDB_ERR_OPERATIONS_ERROR;
1609         }
1610         ac = talloc_get_type(h->private_data, struct ph_context);
1611
1612         /* return or own handle to deal with this call */
1613         req->handle = h;
1614
1615         /* prepare the first operation */
1616         ac->down_req = talloc_zero(ac, struct ldb_request);
1617         if (ac->down_req == NULL) {
1618                 ldb_set_errstring(module->ldb, "Out of memory!");
1619                 return LDB_ERR_OPERATIONS_ERROR;
1620         }
1621
1622         *(ac->down_req) = *req; /* copy the request */
1623
1624         /* use a new message structure so that we can modify it */
1625         ac->down_req->op.mod.message = msg = ldb_msg_copy_shallow(ac->down_req, req->op.mod.message);
1626
1627         /* - remove any imodification to the password from the first commit
1628          *   we will make the real modification later */
1629         if (sambaAttr) ldb_msg_remove_attr(msg, "userPassword");
1630         if (ntAttr) ldb_msg_remove_attr(msg, "unicodePwd");
1631         if (lmAttr) ldb_msg_remove_attr(msg, "dBCSPwd");
1632
1633         /* if there was nothing else to be modify skip to next step */
1634         if (msg->num_elements == 0) {
1635                 talloc_free(ac->down_req);
1636                 ac->down_req = NULL;
1637                 return password_hash_mod_search_self(h);
1638         }
1639         
1640         ac->down_req->context = NULL;
1641         ac->down_req->callback = NULL;
1642
1643         ac->step = PH_MOD_DO_REQ;
1644
1645         ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
1646
1647         return ldb_next_request(module, ac->down_req);
1648 }
1649
1650 static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
1651 {
1652         struct ph_context *ac;
1653
1654         ac = talloc_get_type(context, struct ph_context);
1655
1656         /* we are interested only in the single reply (base search) we receive here */
1657         if (ares->type == LDB_REPLY_ENTRY) {
1658                 if (ac->search_res != NULL) {
1659                         ldb_set_errstring(ldb, "Too many results");
1660                         talloc_free(ares);
1661                         return LDB_ERR_OPERATIONS_ERROR;
1662                 }
1663
1664                 /* if it is not an entry of type person this is an error */
1665                 /* TODO: remove this when userPassword will be in schema */
1666                 if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
1667                         ldb_set_errstring(ldb, "Object class violation");
1668                         talloc_free(ares);
1669                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
1670                 }
1671
1672                 ac->search_res = talloc_steal(ac, ares);
1673         } else {
1674                 talloc_free(ares);
1675         }
1676
1677         return LDB_SUCCESS;
1678 }
1679
1680 static int password_hash_mod_search_self(struct ldb_handle *h) {
1681
1682         struct ph_context *ac;
1683         static const char * const attrs[] = { "userAccountControl", "lmPwdHistory", 
1684                                               "ntPwdHistory", 
1685                                               "objectSid", "msDS-KeyVersionNumber", 
1686                                               "objectClass", "userPrincipalName",
1687                                               "sAMAccountName", 
1688                                               "dBCSPwd", "unicodePwd",
1689                                               "supplementalCredentials",
1690                                               NULL };
1691
1692         ac = talloc_get_type(h->private_data, struct ph_context);
1693
1694         /* prepare the search operation */
1695         ac->search_req = talloc_zero(ac, struct ldb_request);
1696         if (ac->search_req == NULL) {
1697                 ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
1698                 return LDB_ERR_OPERATIONS_ERROR;
1699         }
1700
1701         ac->search_req->operation = LDB_SEARCH;
1702         ac->search_req->op.search.base = ac->orig_req->op.mod.message->dn;
1703         ac->search_req->op.search.scope = LDB_SCOPE_BASE;
1704         ac->search_req->op.search.tree = ldb_parse_tree(ac->search_req, NULL);
1705         if (ac->search_req->op.search.tree == NULL) {
1706                 ldb_set_errstring(ac->module->ldb, "Invalid search filter");
1707                 return LDB_ERR_OPERATIONS_ERROR;
1708         }
1709         ac->search_req->op.search.attrs = attrs;
1710         ac->search_req->controls = NULL;
1711         ac->search_req->context = ac;
1712         ac->search_req->callback = get_self_callback;
1713         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
1714
1715         ac->step = PH_MOD_SEARCH_SELF;
1716
1717         return ldb_next_request(ac->module, ac->search_req);
1718 }
1719
1720 static int password_hash_mod_search_dom(struct ldb_handle *h) {
1721
1722         struct ph_context *ac;
1723         int ret;
1724
1725         ac = talloc_get_type(h->private_data, struct ph_context);
1726
1727         /* get object domain sid */
1728         ac->domain_sid = samdb_result_sid_prefix(ac, ac->search_res->message, "objectSid");
1729         if (ac->domain_sid == NULL) {
1730                 ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "can't handle entry with missing objectSid!\n");
1731                 return LDB_ERR_OPERATIONS_ERROR;
1732         }
1733
1734         /* get user domain data */
1735         ret = build_domain_data_request(ac);
1736         if (ret != LDB_SUCCESS) {
1737                 return ret;
1738         }
1739
1740         ac->step = PH_MOD_SEARCH_DOM;
1741
1742         return ldb_next_request(ac->module, ac->dom_req);
1743 }
1744
1745 static int password_hash_mod_do_mod(struct ldb_handle *h) {
1746
1747         struct ph_context *ac;
1748         struct domain_data *domain;
1749         struct smb_krb5_context *smb_krb5_context;
1750         struct ldb_message *msg;
1751         struct ldb_message *orig_msg;
1752         struct ldb_message *searched_msg;
1753         struct setup_password_fields_io io;
1754         int ret;
1755
1756         ac = talloc_get_type(h->private_data, struct ph_context);
1757
1758         domain = get_domain_data(ac->module, ac, ac->dom_res);
1759         if (domain == NULL) {
1760                 return LDB_ERR_OPERATIONS_ERROR;
1761         }
1762
1763         ac->mod_req = talloc(ac, struct ldb_request);
1764         if (ac->mod_req == NULL) {
1765                 return LDB_ERR_OPERATIONS_ERROR;
1766         }
1767
1768         *(ac->mod_req) = *(ac->orig_req);
1769         
1770         /* use a new message structure so that we can modify it */
1771         ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
1772         if (msg == NULL) {
1773                 return LDB_ERR_OPERATIONS_ERROR;
1774         }
1775
1776         /* modify dn */
1777         msg->dn = ac->orig_req->op.mod.message->dn;
1778
1779         /* Some operations below require kerberos contexts */
1780         if (smb_krb5_init_context(ac->mod_req, 
1781                                   ldb_get_opaque(h->module->ldb, "EventContext"), 
1782                                   (struct loadparm_context *)ldb_get_opaque(h->module->ldb, "loadparm"), 
1783                                   &smb_krb5_context) != 0) {
1784                 return LDB_ERR_OPERATIONS_ERROR;
1785         }
1786
1787         orig_msg        = discard_const(ac->orig_req->op.mod.message);
1788         searched_msg    = ac->search_res->message;
1789
1790         ZERO_STRUCT(io);
1791         io.ac                           = ac;
1792         io.domain                       = domain;
1793         io.smb_krb5_context             = smb_krb5_context;
1794
1795         io.u.user_account_control       = samdb_result_uint(searched_msg, "userAccountControl", 0);
1796         io.u.sAMAccountName             = samdb_result_string(searched_msg, "samAccountName", NULL);
1797         io.u.user_principal_name        = samdb_result_string(searched_msg, "userPrincipalName", NULL);
1798         io.u.is_computer                = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
1799
1800         io.n.cleartext                  = samdb_result_string(orig_msg, "userPassword", NULL);
1801         io.n.nt_hash                    = samdb_result_hash(io.ac, orig_msg, "unicodePwd");
1802         io.n.lm_hash                    = samdb_result_hash(io.ac, orig_msg, "dBCSPwd");
1803
1804         io.o.kvno                       = samdb_result_uint(searched_msg, "msDs-KeyVersionNumber", 0);
1805         io.o.nt_history_len             = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history);
1806         io.o.lm_history_len             = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history);
1807         io.o.supplemental               = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials");
1808
1809         ret = setup_password_fields(&io);
1810         if (ret != LDB_SUCCESS) {
1811                 return ret;
1812         }
1813
1814         /* make sure we replace all the old attributes */
1815         ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL);
1816         ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL);
1817         ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
1818         ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL);
1819         ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL);
1820         ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL);
1821         ret = ldb_msg_add_empty(msg, "msDs-KeyVersionNumber", LDB_FLAG_MOD_REPLACE, NULL);
1822
1823         if (io.g.nt_hash) {
1824                 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
1825                                          "unicodePwd", io.g.nt_hash);
1826                 if (ret != LDB_SUCCESS) {
1827                         return ret;
1828                 }
1829         }
1830         if (io.g.lm_hash) {
1831                 ret = samdb_msg_add_hash(ac->module->ldb, ac, msg,
1832                                          "dBCSPwd", io.g.lm_hash);
1833                 if (ret != LDB_SUCCESS) {
1834                         return ret;
1835                 }
1836         }
1837         if (io.g.nt_history_len > 0) {
1838                 ret = samdb_msg_add_hashes(ac, msg,
1839                                            "ntPwdHistory",
1840                                            io.g.nt_history,
1841                                            io.g.nt_history_len);
1842                 if (ret != LDB_SUCCESS) {
1843                         return ret;
1844                 }
1845         }
1846         if (io.g.lm_history_len > 0) {
1847                 ret = samdb_msg_add_hashes(ac, msg,
1848                                            "lmPwdHistory",
1849                                            io.g.lm_history,
1850                                            io.g.lm_history_len);
1851                 if (ret != LDB_SUCCESS) {
1852                         return ret;
1853                 }
1854         }
1855         if (io.g.supplemental.length > 0) {
1856                 ret = ldb_msg_add_value(msg, "supplementalCredentials",
1857                                         &io.g.supplemental, NULL);
1858                 if (ret != LDB_SUCCESS) {
1859                         return ret;
1860                 }
1861         }
1862         ret = samdb_msg_add_uint64(ac->module->ldb, ac, msg,
1863                                    "pwdLastSet",
1864                                    io.g.last_set);
1865         if (ret != LDB_SUCCESS) {
1866                 return ret;
1867         }
1868         ret = samdb_msg_add_uint(ac->module->ldb, ac, msg,
1869                                  "msDs-KeyVersionNumber",
1870                                  io.g.kvno);
1871         if (ret != LDB_SUCCESS) {
1872                 return ret;
1873         }
1874
1875         h->state = LDB_ASYNC_INIT;
1876         h->status = LDB_SUCCESS;
1877
1878         ac->step = PH_MOD_DO_MOD;
1879
1880         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req);
1881
1882         /* perform the search */
1883         return ldb_next_request(ac->module, ac->mod_req);
1884 }
1885
1886 static int ph_wait(struct ldb_handle *handle) {
1887         struct ph_context *ac;
1888         int ret;
1889     
1890         if (!handle || !handle->private_data) {
1891                 return LDB_ERR_OPERATIONS_ERROR;
1892         }
1893
1894         if (handle->state == LDB_ASYNC_DONE) {
1895                 return handle->status;
1896         }
1897
1898         handle->state = LDB_ASYNC_PENDING;
1899         handle->status = LDB_SUCCESS;
1900
1901         ac = talloc_get_type(handle->private_data, struct ph_context);
1902
1903         switch (ac->step) {
1904         case PH_ADD_SEARCH_DOM:
1905                 ret = ldb_wait(ac->dom_req->handle, LDB_WAIT_NONE);
1906
1907                 if (ret != LDB_SUCCESS) {
1908                         handle->status = ret;
1909                         goto done;
1910                 }
1911                 if (ac->dom_req->handle->status != LDB_SUCCESS) {
1912                         handle->status = ac->dom_req->handle->status;
1913                         goto done;
1914                 }
1915
1916                 if (ac->dom_req->handle->state != LDB_ASYNC_DONE) {
1917                         return LDB_SUCCESS;
1918                 }
1919
1920                 /* domain search done, go on */
1921                 return password_hash_add_do_add(handle);
1922
1923         case PH_ADD_DO_ADD:
1924                 ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
1925
1926                 if (ret != LDB_SUCCESS) {
1927                         handle->status = ret;
1928                         goto done;
1929                 }
1930                 if (ac->down_req->handle->status != LDB_SUCCESS) {
1931                         handle->status = ac->down_req->handle->status;
1932                         goto done;
1933                 }
1934
1935                 if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
1936                         return LDB_SUCCESS;
1937                 }
1938
1939                 break;
1940                 
1941         case PH_MOD_DO_REQ:
1942                 ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
1943
1944                 if (ret != LDB_SUCCESS) {
1945                         handle->status = ret;
1946                         goto done;
1947                 }
1948                 if (ac->down_req->handle->status != LDB_SUCCESS) {
1949                         handle->status = ac->down_req->handle->status;
1950                         goto done;
1951                 }
1952
1953                 if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
1954                         return LDB_SUCCESS;
1955                 }
1956
1957                 /* non-password mods done, go on */
1958                 return password_hash_mod_search_self(handle);
1959                 
1960         case PH_MOD_SEARCH_SELF:
1961                 ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
1962
1963                 if (ret != LDB_SUCCESS) {
1964                         handle->status = ret;
1965                         goto done;
1966                 }
1967                 if (ac->search_req->handle->status != LDB_SUCCESS) {
1968                         handle->status = ac->search_req->handle->status;
1969                         goto done;
1970                 }
1971
1972                 if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
1973                         return LDB_SUCCESS;
1974                 }
1975
1976                 if (ac->search_res == NULL) {
1977                         return LDB_ERR_NO_SUCH_OBJECT;
1978                 }
1979
1980                 /* self search done, go on */
1981                 return password_hash_mod_search_dom(handle);
1982                 
1983         case PH_MOD_SEARCH_DOM:
1984                 ret = ldb_wait(ac->dom_req->handle, LDB_WAIT_NONE);
1985
1986                 if (ret != LDB_SUCCESS) {
1987                         handle->status = ret;
1988                         goto done;
1989                 }
1990                 if (ac->dom_req->handle->status != LDB_SUCCESS) {
1991                         handle->status = ac->dom_req->handle->status;
1992                         goto done;
1993                 }
1994
1995                 if (ac->dom_req->handle->state != LDB_ASYNC_DONE) {
1996                         return LDB_SUCCESS;
1997                 }
1998
1999                 /* domain search done, go on */
2000                 return password_hash_mod_do_mod(handle);
2001
2002         case PH_MOD_DO_MOD:
2003                 ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
2004
2005                 if (ret != LDB_SUCCESS) {
2006                         handle->status = ret;
2007                         goto done;
2008                 }
2009                 if (ac->mod_req->handle->status != LDB_SUCCESS) {
2010                         handle->status = ac->mod_req->handle->status;
2011                         goto done;
2012                 }
2013
2014                 if (ac->mod_req->handle->state != LDB_ASYNC_DONE) {
2015                         return LDB_SUCCESS;
2016                 }
2017
2018                 break;
2019                 
2020         default:
2021                 ret = LDB_ERR_OPERATIONS_ERROR;
2022                 goto done;
2023         }
2024
2025         ret = LDB_SUCCESS;
2026
2027 done:
2028         handle->state = LDB_ASYNC_DONE;
2029         return ret;
2030 }
2031
2032 static int ph_wait_all(struct ldb_handle *handle) {
2033
2034         int ret;
2035
2036         while (handle->state != LDB_ASYNC_DONE) {
2037                 ret = ph_wait(handle);
2038                 if (ret != LDB_SUCCESS) {
2039                         return ret;
2040                 }
2041         }
2042
2043         return handle->status;
2044 }
2045
2046 static int password_hash_wait(struct ldb_handle *handle, enum ldb_wait_type type)
2047 {
2048         if (type == LDB_WAIT_ALL) {
2049                 return ph_wait_all(handle);
2050         } else {
2051                 return ph_wait(handle);
2052         }
2053 }
2054
2055 _PUBLIC_ const struct ldb_module_ops ldb_password_hash_module_ops = {
2056         .name          = "password_hash",
2057         .add           = password_hash_add,
2058         .modify        = password_hash_modify,
2059         .wait          = password_hash_wait
2060 };