60d538369bfe0c62291fc2038602b269708270bb
[samba.git] / source4 / libnet / libnet_passwd.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    Copyright (C) Stefan Metzmacher      2004
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "libnet/libnet.h"
23 #include "librpc/gen_ndr/ndr_samr.h"
24 #include "lib/crypto/crypto.h"
25
26 /*
27  * do a password change using DCERPC/SAMR calls
28  * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
29  * 2. try samr_ChangePasswordUser3
30  * 3. try samr_ChangePasswordUser2
31  * 4. try samr_OemChangePasswordUser2
32  * (not yet: 5. try samr_ChangePasswordUser)
33  */
34 static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
35 {
36         NTSTATUS status;
37         union libnet_rpc_connect c;
38 #if 0
39         struct policy_handle user_handle;
40         struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
41         struct samr_ChangePasswordUser pw;
42 #endif
43         struct samr_OemChangePasswordUser2 oe2;
44         struct samr_ChangePasswordUser2 pw2;
45         struct samr_ChangePasswordUser3 pw3;
46         struct samr_String server, account;
47         struct samr_AsciiName a_server, a_account;
48         struct samr_CryptPassword nt_pass, lm_pass;
49         struct samr_Password nt_verifier, lm_verifier;
50         uint8_t old_nt_hash[16], new_nt_hash[16];
51         uint8_t old_lm_hash[16], new_lm_hash[16];
52
53         /* prepare connect to the SAMR pipe of the users domain PDC */
54         c.pdc.level                     = LIBNET_RPC_CONNECT_PDC;
55         c.pdc.in.domain_name            = r->samr.in.domain_name;
56         c.pdc.in.dcerpc_iface_name      = DCERPC_SAMR_NAME;
57         c.pdc.in.dcerpc_iface_uuid      = DCERPC_SAMR_UUID;
58         c.pdc.in.dcerpc_iface_version   = DCERPC_SAMR_VERSION;
59
60         /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
61         status = libnet_rpc_connect(ctx, mem_ctx, &c);
62         if (!NT_STATUS_IS_OK(status)) {
63                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
64                                                 "Connection to SAMR pipe of PDC of domain '%s' failed: %s\n",
65                                                 r->samr.in.domain_name, nt_errstr(status));
66                 return status;
67         }
68
69         /* prepare password change for account */
70         server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.pdc.out.dcerpc_pipe));
71         account.string = r->samr.in.account_name;
72
73         E_md4hash(r->samr.in.oldpassword, old_nt_hash);
74         E_md4hash(r->samr.in.newpassword, new_nt_hash);
75
76         E_deshash(r->samr.in.oldpassword, old_lm_hash);
77         E_deshash(r->samr.in.newpassword, new_lm_hash);
78
79         /* prepare samr_ChangePasswordUser3 */
80         encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_UNICODE);
81         arcfour_crypt(lm_pass.data, old_nt_hash, 516);
82         E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
83
84         encode_pw_buffer(nt_pass.data,  r->samr.in.newpassword, STR_UNICODE);
85         arcfour_crypt(nt_pass.data, old_nt_hash, 516);
86         E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
87
88         pw3.in.server = &server;
89         pw3.in.account = &account;
90         pw3.in.nt_password = &nt_pass;
91         pw3.in.nt_verifier = &nt_verifier;
92         pw3.in.lm_change = 1;
93         pw3.in.lm_password = &lm_pass;
94         pw3.in.lm_verifier = &lm_verifier;
95         pw3.in.password3 = NULL;
96
97         /* 2. try samr_ChangePasswordUser3 */
98         status = dcerpc_samr_ChangePasswordUser3(c.pdc.out.dcerpc_pipe, mem_ctx, &pw3);
99         if (!NT_STATUS_IS_OK(status)) {
100                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
101                                                 "samr_ChangePasswordUser3 failed: %s\n",
102                                                 nt_errstr(status));
103                 goto ChangePasswordUser2;
104         }
105
106         /* check result of samr_ChangePasswordUser3 */
107         if (!NT_STATUS_IS_OK(pw3.out.result)) {
108                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
109                                                 "samr_ChangePasswordUser3 for '%s\\%s' failed: %s\n",
110                                                 r->samr.in.domain_name, r->samr.in.account_name, 
111                                                 nt_errstr(pw3.out.result));
112                                                 /* TODO: give the reason of the reject */
113                 if (NT_STATUS_EQUAL(pw3.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
114                         status = pw3.out.result;
115                         goto disconnect;
116                 }
117                 goto ChangePasswordUser2;
118         }
119
120         goto disconnect;
121
122 ChangePasswordUser2:
123         /* prepare samr_ChangePasswordUser2 */
124         encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII|STR_TERMINATE);
125         arcfour_crypt(lm_pass.data, old_lm_hash, 516);
126         E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
127
128         encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE);
129         arcfour_crypt(nt_pass.data, old_nt_hash, 516);
130         E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
131
132         pw2.in.server = &server;
133         pw2.in.account = &account;
134         pw2.in.nt_password = &nt_pass;
135         pw2.in.nt_verifier = &nt_verifier;
136         pw2.in.lm_change = 1;
137         pw2.in.lm_password = &lm_pass;
138         pw2.in.lm_verifier = &lm_verifier;
139
140         /* 3. try samr_ChangePasswordUser2 */
141         status = dcerpc_samr_ChangePasswordUser2(c.pdc.out.dcerpc_pipe, mem_ctx, &pw2);
142         if (!NT_STATUS_IS_OK(status)) {
143                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
144                                                 "samr_ChangePasswordUser2 failed: %s\n",
145                                                 nt_errstr(status));
146                 goto OemChangePasswordUser2;
147         }
148
149         /* check result of samr_ChangePasswordUser2 */
150         if (!NT_STATUS_IS_OK(pw2.out.result)) {
151                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
152                                                 "samr_ChangePasswordUser2 for '%s\\%s' failed: %s\n",
153                                                 r->samr.in.domain_name, r->samr.in.account_name, 
154                                                 nt_errstr(pw2.out.result));
155                 if (NT_STATUS_EQUAL(pw2.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
156                         status = pw2.out.result;
157                         goto disconnect;
158                 }
159                 goto OemChangePasswordUser2;
160         }
161
162         goto disconnect;
163
164 OemChangePasswordUser2:
165         /* prepare samr_OemChangePasswordUser2 */
166         a_server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.pdc.out.dcerpc_pipe));
167         a_account.string = r->samr.in.account_name;
168
169         encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII);
170         arcfour_crypt(lm_pass.data, old_lm_hash, 516);
171         E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
172
173         oe2.in.server = &a_server;
174         oe2.in.account = &a_account;
175         oe2.in.password = &lm_pass;
176         oe2.in.hash = &lm_verifier;
177
178         /* 4. try samr_OemChangePasswordUser2 */
179         status = dcerpc_samr_OemChangePasswordUser2(c.pdc.out.dcerpc_pipe, mem_ctx, &oe2);
180         if (!NT_STATUS_IS_OK(status)) {
181                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
182                                                 "samr_OemChangePasswordUser2 failed: %s\n",
183                                                 nt_errstr(status));
184                 goto ChangePasswordUser;
185         }
186
187         /* check result of samr_OemChangePasswordUser2 */
188         if (!NT_STATUS_IS_OK(oe2.out.result)) {
189                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
190                                                 "samr_OemChangePasswordUser2 for '%s\\%s' failed: %s\n",
191                                                 r->samr.in.domain_name, r->samr.in.account_name, 
192                                                 nt_errstr(oe2.out.result));
193                 if (NT_STATUS_EQUAL(oe2.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
194                         status = oe2.out.result;
195                         goto disconnect;
196                 }
197                 goto ChangePasswordUser;
198         }
199
200         goto disconnect;
201
202 ChangePasswordUser:
203 #if 0
204         /* prepare samr_ChangePasswordUser */
205         E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
206         E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
207         E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
208         E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
209         E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
210         E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
211
212         /* TODO: ask for a user_handle */
213         pw.in.handle = &user_handle;
214         pw.in.lm_present = 1;
215         pw.in.old_lm_crypted = &hash1;
216         pw.in.new_lm_crypted = &hash2;
217         pw.in.nt_present = 1;
218         pw.in.old_nt_crypted = &hash3;
219         pw.in.new_nt_crypted = &hash4;
220         pw.in.cross1_present = 1;
221         pw.in.nt_cross = &hash5;
222         pw.in.cross2_present = 1;
223         pw.in.lm_cross = &hash6;
224
225         /* 5. try samr_ChangePasswordUser */
226         status = dcerpc_samr_ChangePasswordUser(c.pdc.out.dcerpc_pipe, mem_ctx, &pw);
227         if (!NT_STATUS_IS_OK(status)) {
228                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
229                                                 "samr_ChangePasswordUser failed: %s\n",
230                                                 nt_errstr(status));
231                 goto disconnect;
232         }
233
234         /* check result of samr_ChangePasswordUser */
235         if (!NT_STATUS_IS_OK(pw.out.result)) {
236                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
237                                                 "samr_ChangePasswordUser for '%s\\%s' failed: %s\n",
238                                                 r->samr.in.domain_name, r->samr.in.account_name, 
239                                                 nt_errstr(pw.out.result));
240                 if (NT_STATUS_EQUAL(pw.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
241                         status = pw.out.result;
242                         goto disconnect;
243                 }
244                 goto disconnect;
245         }
246 #endif
247 disconnect:
248         /* close connection */
249         dcerpc_pipe_close(c.pdc.out.dcerpc_pipe);
250
251         return status;
252 }
253
254 static NTSTATUS libnet_ChangePassword_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
255 {
256         NTSTATUS status;
257         union libnet_ChangePassword r2;
258
259         r2.samr.level           = LIBNET_CHANGE_PASSWORD_SAMR;
260         r2.samr.in.account_name = r->generic.in.account_name;
261         r2.samr.in.domain_name  = r->generic.in.domain_name;
262         r2.samr.in.oldpassword  = r->generic.in.oldpassword;
263         r2.samr.in.newpassword  = r->generic.in.newpassword;
264
265         status = libnet_ChangePassword(ctx, mem_ctx, &r2);
266
267         r->generic.out.error_string = r2.samr.out.error_string;
268
269         return status;
270 }
271
272 NTSTATUS libnet_ChangePassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
273 {
274         switch (r->generic.level) {
275                 case LIBNET_CHANGE_PASSWORD_GENERIC:
276                         return libnet_ChangePassword_generic(ctx, mem_ctx, r);
277                 case LIBNET_CHANGE_PASSWORD_SAMR:
278                         return libnet_ChangePassword_samr(ctx, mem_ctx, r);
279                 case LIBNET_CHANGE_PASSWORD_KRB5:
280                         return NT_STATUS_NOT_IMPLEMENTED;
281                 case LIBNET_CHANGE_PASSWORD_LDAP:
282                         return NT_STATUS_NOT_IMPLEMENTED;
283                 case LIBNET_CHANGE_PASSWORD_RAP:
284                         return NT_STATUS_NOT_IMPLEMENTED;
285         }
286
287         return NT_STATUS_INVALID_LEVEL;
288 }
289
290 /*
291  * set a password with DCERPC/SAMR calls
292  * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
293  *    is it correct to contact the the pdc of the domain of the user who's password should be set?
294  * 2. do a samr_Connect to get a policy handle
295  * 3. do a samr_LookupDomain to get the domain sid
296  * 4. do a samr_OpenDomain to get a domain handle
297  * 5. do a samr_LookupNames to get the users rid
298  * 6. do a samr_OpenUser to get a user handle
299  * 7. try samr_SetUserInfo level 26 to set the password
300  * 8. try samr_SetUserInfo level 25 to set the password
301  * 8. try samr_SetUserInfo level 24 to set the password
302  *10. try samr_SetUserInfo level 23 to set the password
303  */
304 static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
305 {
306         NTSTATUS status;
307         union libnet_rpc_connect c;
308         struct samr_Connect sc;
309         struct policy_handle p_handle;
310         struct samr_LookupDomain ld;
311         struct samr_String d_name;
312         struct samr_OpenDomain od;
313         struct policy_handle d_handle;
314         struct samr_LookupNames ln;
315         struct samr_OpenUser ou;
316         struct policy_handle u_handle;
317         struct samr_SetUserInfo sui;
318         union samr_UserInfo u_info;
319         DATA_BLOB session_key;
320         DATA_BLOB confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
321         uint8_t confounder[16]; 
322         struct MD5Context md5;
323
324         /* prepare connect to the SAMR pipe of users domain PDC */
325         c.pdc.level                     = LIBNET_RPC_CONNECT_PDC;
326         c.pdc.in.domain_name            = r->samr.in.domain_name;
327         c.pdc.in.dcerpc_iface_name      = DCERPC_SAMR_NAME;
328         c.pdc.in.dcerpc_iface_uuid      = DCERPC_SAMR_UUID;
329         c.pdc.in.dcerpc_iface_version   = DCERPC_SAMR_VERSION;
330
331         /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
332         status = libnet_rpc_connect(ctx, mem_ctx, &c);
333         if (!NT_STATUS_IS_OK(status)) {
334                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
335                                                 "Connection to SAMR pipe of PDC of domain '%s' failed: %s\n",
336                                                 r->samr.in.domain_name, nt_errstr(status));
337                 return status;
338         }
339
340         /* prepare samr_Connect */
341         ZERO_STRUCT(p_handle);
342         sc.in.system_name = NULL;
343         sc.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
344         sc.out.connect_handle = &p_handle;
345
346         /* 2. do a samr_Connect to get a policy handle */
347         status = dcerpc_samr_Connect(c.pdc.out.dcerpc_pipe, mem_ctx, &sc);
348         if (!NT_STATUS_IS_OK(status)) {
349                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
350                                                 "samr_Connect failed: %s\n",
351                                                 nt_errstr(status));
352                 goto disconnect;
353         }
354
355         /* check result of samr_Connect */
356         if (!NT_STATUS_IS_OK(sc.out.result)) {
357                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
358                                                 "samr_Connect failed: %s\n", 
359                                                 nt_errstr(sc.out.result));
360                 status = sc.out.result;
361                 goto disconnect;
362         }
363
364         /* prepare samr_LookupDomain */
365         d_name.string = r->samr.in.domain_name;
366         ld.in.connect_handle = &p_handle;
367         ld.in.domain = &d_name;
368
369         /* 3. do a samr_LookupDomain to get the domain sid */
370         status = dcerpc_samr_LookupDomain(c.pdc.out.dcerpc_pipe, mem_ctx, &ld);
371         if (!NT_STATUS_IS_OK(status)) {
372                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
373                                                 "samr_LookupDomain for [%s] failed: %s\n",
374                                                 r->samr.in.domain_name, nt_errstr(status));
375                 goto disconnect;
376         }
377
378         /* check result of samr_LookupDomain */
379         if (!NT_STATUS_IS_OK(ld.out.result)) {
380                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
381                                                 "samr_LookupDomain for [%s] failed: %s\n",
382                                                 r->samr.in.domain_name, nt_errstr(ld.out.result));
383                 status = ld.out.result;
384                 goto disconnect;
385         }
386
387         /* prepare samr_OpenDomain */
388         ZERO_STRUCT(d_handle);
389         od.in.connect_handle = &p_handle;
390         od.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
391         od.in.sid = ld.out.sid;
392         od.out.domain_handle = &d_handle;
393
394         /* 4. do a samr_OpenDomain to get a domain handle */
395         status = dcerpc_samr_OpenDomain(c.pdc.out.dcerpc_pipe, mem_ctx, &od);
396         if (!NT_STATUS_IS_OK(status)) {
397                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
398                                                 "samr_OpenDomain for [%s] failed: %s\n",
399                                                 r->samr.in.domain_name, nt_errstr(status));
400                 goto disconnect;
401         }
402
403         /* check result of samr_OpenDomain */
404         if (!NT_STATUS_IS_OK(od.out.result)) {
405                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
406                                                 "samr_OpenDomain for [%s] failed: %s\n",
407                                                 r->samr.in.domain_name, nt_errstr(od.out.result));
408                 status = od.out.result;
409                 goto disconnect;
410         }
411
412         /* prepare samr_LookupNames */
413         ln.in.domain_handle = &d_handle;
414         ln.in.num_names = 1;
415         ln.in.names = talloc_array_p(mem_ctx, struct samr_String, 1);
416         if (!ln.in.names) {
417                 r->samr.out.error_string = "Out of Memory";
418                 return NT_STATUS_NO_MEMORY;
419         }
420         ln.in.names[0].string = r->samr.in.account_name;
421
422         /* 5. do a samr_LookupNames to get the users rid */
423         status = dcerpc_samr_LookupNames(c.pdc.out.dcerpc_pipe, mem_ctx, &ln);
424         if (!NT_STATUS_IS_OK(status)) {
425                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
426                                                 "samr_LookupNames for [%s] failed: %s\n",
427                                                 r->samr.in.account_name, nt_errstr(status));
428                 goto disconnect;
429         }
430
431         /* check result of samr_LookupNames */
432         if (!NT_STATUS_IS_OK(ln.out.result)) {
433                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
434                                                 "samr_LookupNames for [%s] failed: %s\n",
435                                                 r->samr.in.account_name, nt_errstr(ln.out.result));
436                 status = ln.out.result;
437                 goto disconnect;
438         }
439
440         /* check if we got one RID for the user */
441         if (ln.out.rids.count != 1) {
442                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
443                                                 "samr_LookupNames for [%s] returns %d RIDs\n",
444                                                 r->samr.in.account_name, ln.out.rids.count);
445                 status = NT_STATUS_INVALID_PARAMETER;
446                 goto disconnect;        
447         }
448
449         /* prepare samr_OpenUser */
450         ZERO_STRUCT(u_handle);
451         ou.in.domain_handle = &d_handle;
452         ou.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
453         ou.in.rid = ln.out.rids.ids[0];
454         ou.out.user_handle = &u_handle;
455
456         /* 6. do a samr_OpenUser to get a user handle */
457         status = dcerpc_samr_OpenUser(c.pdc.out.dcerpc_pipe, mem_ctx, &ou);
458         if (!NT_STATUS_IS_OK(status)) {
459                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
460                                                 "samr_OpenUser for [%s] failed: %s\n",
461                                                 r->samr.in.account_name, nt_errstr(status));
462                 goto disconnect;
463         }
464
465         /* check result of samr_OpenUser */
466         if (!NT_STATUS_IS_OK(ou.out.result)) {
467                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
468                                                 "samr_OpenUser for [%s] failed: %s\n",
469                                                 r->samr.in.account_name, nt_errstr(ou.out.result));
470                 status = ou.out.result;
471                 goto disconnect;
472         }
473
474         /* prepare samr_SetUserInfo level 26 */
475         ZERO_STRUCT(u_info);
476         encode_pw_buffer(u_info.info26.password.data, r->samr.in.newpassword, STR_UNICODE);
477         u_info.info26.pw_len = strlen(r->samr.in.newpassword);
478
479         status = dcerpc_fetch_session_key(c.pdc.out.dcerpc_pipe, &session_key);
480         if (!NT_STATUS_IS_OK(status)) {
481                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
482                                                 "dcerpc_fetch_session_key failed: %s\n",
483                                                 nt_errstr(status));
484                 goto disconnect;
485         }
486
487         generate_random_buffer((uint8_t *)confounder, 16);
488
489         MD5Init(&md5);
490         MD5Update(&md5, confounder, 16);
491         MD5Update(&md5, session_key.data, session_key.length);
492         MD5Final(confounded_session_key.data, &md5);
493
494         arcfour_crypt_blob(u_info.info26.password.data, 516, &confounded_session_key);
495         memcpy(&u_info.info26.password.data[516], confounder, 16);
496
497         sui.in.user_handle = &u_handle;
498         sui.in.info = &u_info;
499         sui.in.level = 26;
500
501         /* 7. try samr_SetUserInfo level 26 to set the password */
502         status = dcerpc_samr_SetUserInfo(c.pdc.out.dcerpc_pipe, mem_ctx, &sui);
503         if (!NT_STATUS_IS_OK(status)) {
504                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
505                                                 "SetUserInfo level 26 for [%s] failed: %s\n",
506                                                 r->samr.in.account_name, nt_errstr(status));
507                 goto UserInfo25;
508         }
509
510         /* check result of samr_SetUserInfo level 26 */
511         if (!NT_STATUS_IS_OK(sui.out.result)) {
512                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
513                                                 "SetUserInfo level 26 for [%s] failed: %s\n",
514                                                 r->samr.in.account_name, nt_errstr(sui.out.result));
515                 if (NT_STATUS_EQUAL(sui.out.result, NT_STATUS_WRONG_PASSWORD)) {
516                         status = sui.out.result;
517                         goto disconnect;
518                 }
519                 goto UserInfo25;
520         }
521
522         goto disconnect;
523
524 UserInfo25:
525         /* prepare samr_SetUserInfo level 25 */
526         ZERO_STRUCT(u_info);
527         u_info.info25.info.fields_present = SAMR_FIELD_PASSWORD;
528         encode_pw_buffer(u_info.info25.password.data, r->samr.in.newpassword, STR_UNICODE);
529
530         status = dcerpc_fetch_session_key(c.pdc.out.dcerpc_pipe, &session_key);
531         if (!NT_STATUS_IS_OK(status)) {
532                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
533                                                 "dcerpc_fetch_session_key failed: %s\n",
534                                                 nt_errstr(status));
535                 goto disconnect;
536         }
537
538         generate_random_buffer((uint8_t *)confounder, 16);
539
540         MD5Init(&md5);
541         MD5Update(&md5, confounder, 16);
542         MD5Update(&md5, session_key.data, session_key.length);
543         MD5Final(confounded_session_key.data, &md5);
544
545         arcfour_crypt_blob(u_info.info25.password.data, 516, &confounded_session_key);
546         memcpy(&u_info.info25.password.data[516], confounder, 16);
547
548         sui.in.user_handle = &u_handle;
549         sui.in.info = &u_info;
550         sui.in.level = 25;
551
552         /* 8. try samr_SetUserInfo level 25 to set the password */
553         status = dcerpc_samr_SetUserInfo(c.pdc.out.dcerpc_pipe, mem_ctx, &sui);
554         if (!NT_STATUS_IS_OK(status)) {
555                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
556                                                 "SetUserInfo level 25 for [%s] failed: %s\n",
557                                                 r->samr.in.account_name, nt_errstr(status));
558                 goto UserInfo24;
559         }
560
561         /* check result of samr_SetUserInfo level 25 */
562         if (!NT_STATUS_IS_OK(sui.out.result)) {
563                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
564                                                 "SetUserInfo level 25 for [%s] failed: %s\n",
565                                                 r->samr.in.account_name, nt_errstr(sui.out.result));
566                 if (NT_STATUS_EQUAL(sui.out.result, NT_STATUS_WRONG_PASSWORD)) {
567                         status = sui.out.result;
568                         goto disconnect;
569                 }
570                 goto UserInfo24;
571         }
572
573         goto disconnect;
574
575 UserInfo24:
576         /* prepare samr_SetUserInfo level 24 */
577         ZERO_STRUCT(u_info);
578         encode_pw_buffer(u_info.info24.password.data, r->samr.in.newpassword, STR_UNICODE);
579         /* w2k3 ignores this length */
580         u_info.info24.pw_len = strlen_m(r->samr.in.newpassword)*2;
581
582         status = dcerpc_fetch_session_key(c.pdc.out.dcerpc_pipe, &session_key);
583         if (!NT_STATUS_IS_OK(status)) {
584                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
585                                                 "dcerpc_fetch_session_key failed: %s\n",
586                                                 nt_errstr(status));
587                 goto disconnect;
588         }
589
590         arcfour_crypt_blob(u_info.info24.password.data, 516, &session_key);
591
592         sui.in.user_handle = &u_handle;
593         sui.in.info = &u_info;
594         sui.in.level = 24;
595
596         /* 9. try samr_SetUserInfo level 24 to set the password */
597         status = dcerpc_samr_SetUserInfo(c.pdc.out.dcerpc_pipe, mem_ctx, &sui);
598         if (!NT_STATUS_IS_OK(status)) {
599                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
600                                                 "SetUserInfo level 24 for [%s] failed: %s\n",
601                                                 r->samr.in.account_name, nt_errstr(status));
602                 goto UserInfo23;
603         }
604
605         /* check result of samr_SetUserInfo level 24 */
606         if (!NT_STATUS_IS_OK(sui.out.result)) {
607                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
608                                                 "SetUserInfo level 24 for [%s] failed: %s\n",
609                                                 r->samr.in.account_name, nt_errstr(sui.out.result));
610                 if (NT_STATUS_EQUAL(sui.out.result, NT_STATUS_WRONG_PASSWORD)) {
611                         status = sui.out.result;
612                         goto disconnect;
613                 }
614                 goto UserInfo23;
615         }
616
617         goto disconnect;
618
619 UserInfo23:
620         /* prepare samr_SetUserInfo level 23 */
621         ZERO_STRUCT(u_info);
622         u_info.info23.info.fields_present = SAMR_FIELD_PASSWORD;
623         encode_pw_buffer(u_info.info23.password.data, r->samr.in.newpassword, STR_UNICODE);
624
625         status = dcerpc_fetch_session_key(c.pdc.out.dcerpc_pipe, &session_key);
626         if (!NT_STATUS_IS_OK(status)) {
627                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
628                                                 "dcerpc_fetch_session_key failed: %s\n",
629                                                 nt_errstr(status));
630                 goto disconnect;
631         }
632
633         arcfour_crypt_blob(u_info.info23.password.data, 516, &session_key);
634
635         sui.in.user_handle = &u_handle;
636         sui.in.info = &u_info;
637         sui.in.level = 23;
638
639         /* 10. try samr_SetUserInfo level 23 to set the password */
640         status = dcerpc_samr_SetUserInfo(c.pdc.out.dcerpc_pipe, mem_ctx, &sui);
641         if (!NT_STATUS_IS_OK(status)) {
642                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
643                                                 "SetUserInfo level 23 for [%s] failed: %s\n",
644                                                 r->samr.in.account_name, nt_errstr(status));
645                 goto disconnect;
646         }
647
648         /* check result of samr_SetUserInfo level 23 */
649         if (!NT_STATUS_IS_OK(sui.out.result)) {
650                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
651                                                 "SetUserInfo level 23 for [%s] failed: %s\n",
652                                                 r->samr.in.account_name, nt_errstr(sui.out.result));
653                 if (NT_STATUS_EQUAL(sui.out.result, NT_STATUS_WRONG_PASSWORD)) {
654                         status = sui.out.result;
655                         goto disconnect;
656                 }
657                 goto disconnect;
658         }
659
660         goto disconnect;
661
662 disconnect:
663         /* close connection */
664         dcerpc_pipe_close(c.pdc.out.dcerpc_pipe);
665
666         return status;
667 }
668
669 static NTSTATUS libnet_SetPassword_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
670 {
671         NTSTATUS status;
672         union libnet_SetPassword r2;
673
674         r2.samr.level           = LIBNET_SET_PASSWORD_SAMR;
675         r2.samr.in.account_name = r->generic.in.account_name;
676         r2.samr.in.domain_name  = r->generic.in.domain_name;
677         r2.samr.in.newpassword  = r->generic.in.newpassword;
678
679         status = libnet_SetPassword(ctx, mem_ctx, &r2);
680
681         r->generic.out.error_string = r2.samr.out.error_string;
682
683         return status;
684 }
685
686 NTSTATUS libnet_SetPassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
687 {
688         switch (r->generic.level) {
689                 case LIBNET_SET_PASSWORD_GENERIC:
690                         return libnet_SetPassword_generic(ctx, mem_ctx, r);
691                 case LIBNET_SET_PASSWORD_SAMR:
692                         return libnet_SetPassword_samr(ctx, mem_ctx, r);
693                 case LIBNET_SET_PASSWORD_KRB5:
694                         return NT_STATUS_NOT_IMPLEMENTED;
695                 case LIBNET_SET_PASSWORD_LDAP:
696                         return NT_STATUS_NOT_IMPLEMENTED;
697                 case LIBNET_SET_PASSWORD_RAP:
698                         return NT_STATUS_NOT_IMPLEMENTED;
699         }
700
701         return NT_STATUS_INVALID_LEVEL;
702 }