r2545: str_charnum -> strlen_m.
[Samba/gebeck_regimport.git] / source4 / libnet / libnet_passwd.c
blob314ab5028a6b3d9721551fb4cedefb9375b0d19e
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2004
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.
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.
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.
21 #include "includes.h"
24 * do a password change using DCERPC/SAMR calls
25 * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
26 * 2. try samr_ChangePasswordUser3
27 * 3. try samr_ChangePasswordUser2
28 * 4. try samr_OemChangePasswordUser2
29 * (not yet: 5. try samr_ChangePasswordUser)
31 static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
33 NTSTATUS status;
34 union libnet_rpc_connect c;
35 #if 0
36 struct policy_handle user_handle;
37 struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
38 struct samr_ChangePasswordUser pw;
39 #endif
40 struct samr_OemChangePasswordUser2 oe2;
41 struct samr_ChangePasswordUser2 pw2;
42 struct samr_ChangePasswordUser3 pw3;
43 struct samr_Name server, account;
44 struct samr_AsciiName a_server, a_account;
45 struct samr_CryptPassword nt_pass, lm_pass;
46 struct samr_Password nt_verifier, lm_verifier;
47 uint8_t old_nt_hash[16], new_nt_hash[16];
48 uint8_t old_lm_hash[16], new_lm_hash[16];
50 /* prepare connect to the SAMR pipe of the users domain PDC */
51 c.pdc.level = LIBNET_RPC_CONNECT_PDC;
52 c.pdc.in.domain_name = r->samr.in.domain_name;
53 c.pdc.in.dcerpc_iface_name = DCERPC_SAMR_NAME;
54 c.pdc.in.dcerpc_iface_uuid = DCERPC_SAMR_UUID;
55 c.pdc.in.dcerpc_iface_version = DCERPC_SAMR_VERSION;
57 /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
58 status = libnet_rpc_connect(ctx, mem_ctx, &c);
59 if (!NT_STATUS_IS_OK(status)) {
60 r->samr.out.error_string = talloc_asprintf(mem_ctx,
61 "Connection to SAMR pipe of PDC of domain '%s' failed: %s\n",
62 r->samr.in.domain_name, nt_errstr(status));
63 return status;
66 /* prepare password change for account */
67 server.name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.pdc.out.dcerpc_pipe));
68 account.name = r->samr.in.account_name;
70 E_md4hash(r->samr.in.oldpassword, old_nt_hash);
71 E_md4hash(r->samr.in.newpassword, new_nt_hash);
73 E_deshash(r->samr.in.oldpassword, old_lm_hash);
74 E_deshash(r->samr.in.newpassword, new_lm_hash);
76 /* prepare samr_ChangePasswordUser3 */
77 encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_UNICODE);
78 arcfour_crypt(lm_pass.data, old_nt_hash, 516);
79 E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
81 encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE);
82 arcfour_crypt(nt_pass.data, old_nt_hash, 516);
83 E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
85 pw3.in.server = &server;
86 pw3.in.account = &account;
87 pw3.in.nt_password = &nt_pass;
88 pw3.in.nt_verifier = &nt_verifier;
89 pw3.in.lm_change = 1;
90 pw3.in.lm_password = &lm_pass;
91 pw3.in.lm_verifier = &lm_verifier;
92 pw3.in.password3 = NULL;
94 /* 2. try samr_ChangePasswordUser3 */
95 status = dcerpc_samr_ChangePasswordUser3(c.pdc.out.dcerpc_pipe, mem_ctx, &pw3);
96 if (!NT_STATUS_IS_OK(status)) {
97 r->samr.out.error_string = talloc_asprintf(mem_ctx,
98 "samr_ChangePasswordUser3 failed: %s\n",
99 nt_errstr(status));
100 goto ChangePasswordUser2;
103 /* check result of samr_ChangePasswordUser3 */
104 if (!NT_STATUS_IS_OK(pw3.out.result)) {
105 r->samr.out.error_string = talloc_asprintf(mem_ctx,
106 "samr_ChangePasswordUser3 for '%s\\%s' failed: %s\n",
107 r->samr.in.domain_name, r->samr.in.account_name,
108 nt_errstr(pw3.out.result));
109 /* TODO: give the reason of the reject */
110 if (NT_STATUS_EQUAL(pw3.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
111 status = pw3.out.result;
112 goto disconnect;
114 goto ChangePasswordUser2;
117 goto disconnect;
119 ChangePasswordUser2:
120 /* prepare samr_ChangePasswordUser2 */
121 encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII|STR_TERMINATE);
122 arcfour_crypt(lm_pass.data, old_lm_hash, 516);
123 E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
125 encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE);
126 arcfour_crypt(nt_pass.data, old_nt_hash, 516);
127 E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
129 pw2.in.server = &server;
130 pw2.in.account = &account;
131 pw2.in.nt_password = &nt_pass;
132 pw2.in.nt_verifier = &nt_verifier;
133 pw2.in.lm_change = 1;
134 pw2.in.lm_password = &lm_pass;
135 pw2.in.lm_verifier = &lm_verifier;
137 /* 3. try samr_ChangePasswordUser2 */
138 status = dcerpc_samr_ChangePasswordUser2(c.pdc.out.dcerpc_pipe, mem_ctx, &pw2);
139 if (!NT_STATUS_IS_OK(status)) {
140 r->samr.out.error_string = talloc_asprintf(mem_ctx,
141 "samr_ChangePasswordUser2 failed: %s\n",
142 nt_errstr(status));
143 goto OemChangePasswordUser2;
146 /* check result of samr_ChangePasswordUser2 */
147 if (!NT_STATUS_IS_OK(pw2.out.result)) {
148 r->samr.out.error_string = talloc_asprintf(mem_ctx,
149 "samr_ChangePasswordUser2 for '%s\\%s' failed: %s\n",
150 r->samr.in.domain_name, r->samr.in.account_name,
151 nt_errstr(pw2.out.result));
152 if (NT_STATUS_EQUAL(pw2.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
153 status = pw2.out.result;
154 goto disconnect;
156 goto OemChangePasswordUser2;
159 goto disconnect;
161 OemChangePasswordUser2:
162 /* prepare samr_OemChangePasswordUser2 */
163 a_server.name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.pdc.out.dcerpc_pipe));
164 a_account.name = r->samr.in.account_name;
166 encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII);
167 arcfour_crypt(lm_pass.data, old_lm_hash, 516);
168 E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
170 oe2.in.server = &a_server;
171 oe2.in.account = &a_account;
172 oe2.in.password = &lm_pass;
173 oe2.in.hash = &lm_verifier;
175 /* 4. try samr_OemChangePasswordUser2 */
176 status = dcerpc_samr_OemChangePasswordUser2(c.pdc.out.dcerpc_pipe, mem_ctx, &oe2);
177 if (!NT_STATUS_IS_OK(status)) {
178 r->samr.out.error_string = talloc_asprintf(mem_ctx,
179 "samr_OemChangePasswordUser2 failed: %s\n",
180 nt_errstr(status));
181 goto ChangePasswordUser;
184 /* check result of samr_OemChangePasswordUser2 */
185 if (!NT_STATUS_IS_OK(oe2.out.result)) {
186 r->samr.out.error_string = talloc_asprintf(mem_ctx,
187 "samr_OemChangePasswordUser2 for '%s\\%s' failed: %s\n",
188 r->samr.in.domain_name, r->samr.in.account_name,
189 nt_errstr(oe2.out.result));
190 if (NT_STATUS_EQUAL(oe2.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
191 status = oe2.out.result;
192 goto disconnect;
194 goto ChangePasswordUser;
197 goto disconnect;
199 ChangePasswordUser:
200 #if 0
201 /* prepare samr_ChangePasswordUser */
202 E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
203 E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
204 E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
205 E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
206 E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
207 E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
209 /* TODO: ask for a user_handle */
210 pw.in.handle = &user_handle;
211 pw.in.lm_present = 1;
212 pw.in.old_lm_crypted = &hash1;
213 pw.in.new_lm_crypted = &hash2;
214 pw.in.nt_present = 1;
215 pw.in.old_nt_crypted = &hash3;
216 pw.in.new_nt_crypted = &hash4;
217 pw.in.cross1_present = 1;
218 pw.in.nt_cross = &hash5;
219 pw.in.cross2_present = 1;
220 pw.in.lm_cross = &hash6;
222 /* 5. try samr_ChangePasswordUser */
223 status = dcerpc_samr_ChangePasswordUser(c.pdc.out.dcerpc_pipe, mem_ctx, &pw);
224 if (!NT_STATUS_IS_OK(status)) {
225 r->samr.out.error_string = talloc_asprintf(mem_ctx,
226 "samr_ChangePasswordUser failed: %s\n",
227 nt_errstr(status));
228 goto disconnect;
231 /* check result of samr_ChangePasswordUser */
232 if (!NT_STATUS_IS_OK(pw.out.result)) {
233 r->samr.out.error_string = talloc_asprintf(mem_ctx,
234 "samr_ChangePasswordUser for '%s\\%s' failed: %s\n",
235 r->samr.in.domain_name, r->samr.in.account_name,
236 nt_errstr(pw.out.result));
237 if (NT_STATUS_EQUAL(pw.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
238 status = pw.out.result;
239 goto disconnect;
241 goto disconnect;
243 #endif
244 disconnect:
245 /* close connection */
246 dcerpc_pipe_close(c.pdc.out.dcerpc_pipe);
248 return status;
251 static NTSTATUS libnet_ChangePassword_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
253 NTSTATUS status;
254 union libnet_ChangePassword r2;
256 r2.samr.level = LIBNET_CHANGE_PASSWORD_SAMR;
257 r2.samr.in.account_name = r->generic.in.account_name;
258 r2.samr.in.domain_name = r->generic.in.domain_name;
259 r2.samr.in.oldpassword = r->generic.in.oldpassword;
260 r2.samr.in.newpassword = r->generic.in.newpassword;
262 status = libnet_ChangePassword(ctx, mem_ctx, &r2);
264 r->generic.out.error_string = r2.samr.out.error_string;
266 return status;
269 NTSTATUS libnet_ChangePassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
271 switch (r->generic.level) {
272 case LIBNET_CHANGE_PASSWORD_GENERIC:
273 return libnet_ChangePassword_generic(ctx, mem_ctx, r);
274 case LIBNET_CHANGE_PASSWORD_SAMR:
275 return libnet_ChangePassword_samr(ctx, mem_ctx, r);
276 case LIBNET_CHANGE_PASSWORD_KRB5:
277 return NT_STATUS_NOT_IMPLEMENTED;
278 case LIBNET_CHANGE_PASSWORD_LDAP:
279 return NT_STATUS_NOT_IMPLEMENTED;
280 case LIBNET_CHANGE_PASSWORD_RAP:
281 return NT_STATUS_NOT_IMPLEMENTED;
284 return NT_STATUS_INVALID_LEVEL;
288 * set a password with DCERPC/SAMR calls
289 * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
290 * is it correct to contact the the pdc of the domain of the user who's password should be set?
291 * 2. do a samr_Connect to get a policy handle
292 * 3. do a samr_LookupDomain to get the domain sid
293 * 4. do a samr_OpenDomain to get a domain handle
294 * 5. do a samr_LookupNames to get the users rid
295 * 6. do a samr_OpenUser to get a user handle
296 * 7. try samr_SetUserInfo level 26 to set the password
297 * 8. try samr_SetUserInfo level 25 to set the password
298 * 8. try samr_SetUserInfo level 24 to set the password
299 *10. try samr_SetUserInfo level 23 to set the password
301 static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
303 NTSTATUS status;
304 union libnet_rpc_connect c;
305 struct samr_Connect sc;
306 struct policy_handle p_handle;
307 struct samr_LookupDomain ld;
308 struct samr_Name d_name;
309 struct samr_OpenDomain od;
310 struct policy_handle d_handle;
311 struct samr_LookupNames ln;
312 struct samr_OpenUser ou;
313 struct policy_handle u_handle;
314 struct samr_SetUserInfo sui;
315 union samr_UserInfo u_info;
316 DATA_BLOB session_key;
317 DATA_BLOB confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
318 uint8_t confounder[16];
319 struct MD5Context md5;
321 /* prepare connect to the SAMR pipe of users domain PDC */
322 c.pdc.level = LIBNET_RPC_CONNECT_PDC;
323 c.pdc.in.domain_name = r->samr.in.domain_name;
324 c.pdc.in.dcerpc_iface_name = DCERPC_SAMR_NAME;
325 c.pdc.in.dcerpc_iface_uuid = DCERPC_SAMR_UUID;
326 c.pdc.in.dcerpc_iface_version = DCERPC_SAMR_VERSION;
328 /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
329 status = libnet_rpc_connect(ctx, mem_ctx, &c);
330 if (!NT_STATUS_IS_OK(status)) {
331 r->samr.out.error_string = talloc_asprintf(mem_ctx,
332 "Connection to SAMR pipe of PDC of domain '%s' failed: %s\n",
333 r->samr.in.domain_name, nt_errstr(status));
334 return status;
337 /* prepare samr_Connect */
338 ZERO_STRUCT(p_handle);
339 sc.in.system_name = NULL;
340 sc.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
341 sc.out.connect_handle = &p_handle;
343 /* 2. do a samr_Connect to get a policy handle */
344 status = dcerpc_samr_Connect(c.pdc.out.dcerpc_pipe, mem_ctx, &sc);
345 if (!NT_STATUS_IS_OK(status)) {
346 r->samr.out.error_string = talloc_asprintf(mem_ctx,
347 "samr_Connect failed: %s\n",
348 nt_errstr(status));
349 goto disconnect;
352 /* check result of samr_Connect */
353 if (!NT_STATUS_IS_OK(sc.out.result)) {
354 r->samr.out.error_string = talloc_asprintf(mem_ctx,
355 "samr_Connect failed: %s\n",
356 nt_errstr(sc.out.result));
357 status = sc.out.result;
358 goto disconnect;
361 /* prepare samr_LookupDomain */
362 d_name.name = r->samr.in.domain_name;
363 ld.in.connect_handle = &p_handle;
364 ld.in.domain = &d_name;
366 /* 3. do a samr_LookupDomain to get the domain sid */
367 status = dcerpc_samr_LookupDomain(c.pdc.out.dcerpc_pipe, mem_ctx, &ld);
368 if (!NT_STATUS_IS_OK(status)) {
369 r->samr.out.error_string = talloc_asprintf(mem_ctx,
370 "samr_LookupDomain for [%s] failed: %s\n",
371 r->samr.in.domain_name, nt_errstr(status));
372 goto disconnect;
375 /* check result of samr_LookupDomain */
376 if (!NT_STATUS_IS_OK(ld.out.result)) {
377 r->samr.out.error_string = talloc_asprintf(mem_ctx,
378 "samr_LookupDomain for [%s] failed: %s\n",
379 r->samr.in.domain_name, nt_errstr(ld.out.result));
380 status = ld.out.result;
381 goto disconnect;
384 /* prepare samr_OpenDomain */
385 ZERO_STRUCT(d_handle);
386 od.in.connect_handle = &p_handle;
387 od.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
388 od.in.sid = ld.out.sid;
389 od.out.domain_handle = &d_handle;
391 /* 4. do a samr_OpenDomain to get a domain handle */
392 status = dcerpc_samr_OpenDomain(c.pdc.out.dcerpc_pipe, mem_ctx, &od);
393 if (!NT_STATUS_IS_OK(status)) {
394 r->samr.out.error_string = talloc_asprintf(mem_ctx,
395 "samr_OpenDomain for [%s] failed: %s\n",
396 r->samr.in.domain_name, nt_errstr(status));
397 goto disconnect;
400 /* check result of samr_OpenDomain */
401 if (!NT_STATUS_IS_OK(od.out.result)) {
402 r->samr.out.error_string = talloc_asprintf(mem_ctx,
403 "samr_OpenDomain for [%s] failed: %s\n",
404 r->samr.in.domain_name, nt_errstr(od.out.result));
405 status = od.out.result;
406 goto disconnect;
409 /* prepare samr_LookupNames */
410 ln.in.domain_handle = &d_handle;
411 ln.in.num_names = 1;
412 ln.in.names = talloc_array_p(mem_ctx, struct samr_Name, 1);
413 if (!ln.in.names) {
414 r->samr.out.error_string = "Out of Memory";
415 return NT_STATUS_NO_MEMORY;
417 ln.in.names[0].name = r->samr.in.account_name;
419 /* 5. do a samr_LookupNames to get the users rid */
420 status = dcerpc_samr_LookupNames(c.pdc.out.dcerpc_pipe, mem_ctx, &ln);
421 if (!NT_STATUS_IS_OK(status)) {
422 r->samr.out.error_string = talloc_asprintf(mem_ctx,
423 "samr_LookupNames for [%s] failed: %s\n",
424 r->samr.in.account_name, nt_errstr(status));
425 goto disconnect;
428 /* check result of samr_LookupNames */
429 if (!NT_STATUS_IS_OK(ln.out.result)) {
430 r->samr.out.error_string = talloc_asprintf(mem_ctx,
431 "samr_LookupNames for [%s] failed: %s\n",
432 r->samr.in.account_name, nt_errstr(ln.out.result));
433 status = ln.out.result;
434 goto disconnect;
437 /* check if we got one RID for the user */
438 if (ln.out.rids.count != 1) {
439 r->samr.out.error_string = talloc_asprintf(mem_ctx,
440 "samr_LookupNames for [%s] returns %d RIDs\n",
441 r->samr.in.account_name, ln.out.rids.count);
442 status = NT_STATUS_INVALID_PARAMETER;
443 goto disconnect;
446 /* prepare samr_OpenUser */
447 ZERO_STRUCT(u_handle);
448 ou.in.domain_handle = &d_handle;
449 ou.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
450 ou.in.rid = ln.out.rids.ids[0];
451 ou.out.user_handle = &u_handle;
453 /* 6. do a samr_OpenUser to get a user handle */
454 status = dcerpc_samr_OpenUser(c.pdc.out.dcerpc_pipe, mem_ctx, &ou);
455 if (!NT_STATUS_IS_OK(status)) {
456 r->samr.out.error_string = talloc_asprintf(mem_ctx,
457 "samr_OpenUser for [%s] failed: %s\n",
458 r->samr.in.account_name, nt_errstr(status));
459 goto disconnect;
462 /* check result of samr_OpenUser */
463 if (!NT_STATUS_IS_OK(ou.out.result)) {
464 r->samr.out.error_string = talloc_asprintf(mem_ctx,
465 "samr_OpenUser for [%s] failed: %s\n",
466 r->samr.in.account_name, nt_errstr(ou.out.result));
467 status = ou.out.result;
468 goto disconnect;
471 /* prepare samr_SetUserInfo level 26 */
472 ZERO_STRUCT(u_info);
473 encode_pw_buffer(u_info.info26.password.data, r->samr.in.newpassword, STR_UNICODE);
474 u_info.info26.pw_len = strlen(r->samr.in.newpassword);
476 status = dcerpc_fetch_session_key(c.pdc.out.dcerpc_pipe, &session_key);
477 if (!NT_STATUS_IS_OK(status)) {
478 r->samr.out.error_string = talloc_asprintf(mem_ctx,
479 "dcerpc_fetch_session_key failed: %s\n",
480 nt_errstr(status));
481 goto disconnect;
484 generate_random_buffer((uint8_t *)confounder, 16);
486 MD5Init(&md5);
487 MD5Update(&md5, confounder, 16);
488 MD5Update(&md5, session_key.data, session_key.length);
489 MD5Final(confounded_session_key.data, &md5);
491 arcfour_crypt_blob(u_info.info26.password.data, 516, &confounded_session_key);
492 memcpy(&u_info.info26.password.data[516], confounder, 16);
494 sui.in.user_handle = &u_handle;
495 sui.in.info = &u_info;
496 sui.in.level = 26;
498 /* 7. try samr_SetUserInfo level 26 to set the password */
499 status = dcerpc_samr_SetUserInfo(c.pdc.out.dcerpc_pipe, mem_ctx, &sui);
500 if (!NT_STATUS_IS_OK(status)) {
501 r->samr.out.error_string = talloc_asprintf(mem_ctx,
502 "SetUserInfo level 26 for [%s] failed: %s\n",
503 r->samr.in.account_name, nt_errstr(status));
504 goto UserInfo25;
507 /* check result of samr_SetUserInfo level 26 */
508 if (!NT_STATUS_IS_OK(sui.out.result)) {
509 r->samr.out.error_string = talloc_asprintf(mem_ctx,
510 "SetUserInfo level 26 for [%s] failed: %s\n",
511 r->samr.in.account_name, nt_errstr(sui.out.result));
512 if (NT_STATUS_EQUAL(sui.out.result, NT_STATUS_WRONG_PASSWORD)) {
513 status = sui.out.result;
514 goto disconnect;
516 goto UserInfo25;
519 goto disconnect;
521 UserInfo25:
522 /* prepare samr_SetUserInfo level 25 */
523 ZERO_STRUCT(u_info);
524 u_info.info25.info.fields_present = SAMR_FIELD_PASSWORD;
525 encode_pw_buffer(u_info.info25.password.data, r->samr.in.newpassword, STR_UNICODE);
527 status = dcerpc_fetch_session_key(c.pdc.out.dcerpc_pipe, &session_key);
528 if (!NT_STATUS_IS_OK(status)) {
529 r->samr.out.error_string = talloc_asprintf(mem_ctx,
530 "dcerpc_fetch_session_key failed: %s\n",
531 nt_errstr(status));
532 goto disconnect;
535 generate_random_buffer((uint8_t *)confounder, 16);
537 MD5Init(&md5);
538 MD5Update(&md5, confounder, 16);
539 MD5Update(&md5, session_key.data, session_key.length);
540 MD5Final(confounded_session_key.data, &md5);
542 arcfour_crypt_blob(u_info.info25.password.data, 516, &confounded_session_key);
543 memcpy(&u_info.info25.password.data[516], confounder, 16);
545 sui.in.user_handle = &u_handle;
546 sui.in.info = &u_info;
547 sui.in.level = 25;
549 /* 8. try samr_SetUserInfo level 25 to set the password */
550 status = dcerpc_samr_SetUserInfo(c.pdc.out.dcerpc_pipe, mem_ctx, &sui);
551 if (!NT_STATUS_IS_OK(status)) {
552 r->samr.out.error_string = talloc_asprintf(mem_ctx,
553 "SetUserInfo level 25 for [%s] failed: %s\n",
554 r->samr.in.account_name, nt_errstr(status));
555 goto UserInfo24;
558 /* check result of samr_SetUserInfo level 25 */
559 if (!NT_STATUS_IS_OK(sui.out.result)) {
560 r->samr.out.error_string = talloc_asprintf(mem_ctx,
561 "SetUserInfo level 25 for [%s] failed: %s\n",
562 r->samr.in.account_name, nt_errstr(sui.out.result));
563 if (NT_STATUS_EQUAL(sui.out.result, NT_STATUS_WRONG_PASSWORD)) {
564 status = sui.out.result;
565 goto disconnect;
567 goto UserInfo24;
570 goto disconnect;
572 UserInfo24:
573 /* prepare samr_SetUserInfo level 24 */
574 ZERO_STRUCT(u_info);
575 encode_pw_buffer(u_info.info24.password.data, r->samr.in.newpassword, STR_UNICODE);
576 /* w2k3 ignores this length */
577 u_info.info24.pw_len = strlen_m(r->samr.in.newpassword)*2;
579 status = dcerpc_fetch_session_key(c.pdc.out.dcerpc_pipe, &session_key);
580 if (!NT_STATUS_IS_OK(status)) {
581 r->samr.out.error_string = talloc_asprintf(mem_ctx,
582 "dcerpc_fetch_session_key failed: %s\n",
583 nt_errstr(status));
584 goto disconnect;
587 arcfour_crypt_blob(u_info.info24.password.data, 516, &session_key);
589 sui.in.user_handle = &u_handle;
590 sui.in.info = &u_info;
591 sui.in.level = 24;
593 /* 9. try samr_SetUserInfo level 24 to set the password */
594 status = dcerpc_samr_SetUserInfo(c.pdc.out.dcerpc_pipe, mem_ctx, &sui);
595 if (!NT_STATUS_IS_OK(status)) {
596 r->samr.out.error_string = talloc_asprintf(mem_ctx,
597 "SetUserInfo level 24 for [%s] failed: %s\n",
598 r->samr.in.account_name, nt_errstr(status));
599 goto UserInfo23;
602 /* check result of samr_SetUserInfo level 24 */
603 if (!NT_STATUS_IS_OK(sui.out.result)) {
604 r->samr.out.error_string = talloc_asprintf(mem_ctx,
605 "SetUserInfo level 24 for [%s] failed: %s\n",
606 r->samr.in.account_name, nt_errstr(sui.out.result));
607 if (NT_STATUS_EQUAL(sui.out.result, NT_STATUS_WRONG_PASSWORD)) {
608 status = sui.out.result;
609 goto disconnect;
611 goto UserInfo23;
614 goto disconnect;
616 UserInfo23:
617 /* prepare samr_SetUserInfo level 23 */
618 ZERO_STRUCT(u_info);
619 u_info.info23.info.fields_present = SAMR_FIELD_PASSWORD;
620 encode_pw_buffer(u_info.info23.password.data, r->samr.in.newpassword, STR_UNICODE);
622 status = dcerpc_fetch_session_key(c.pdc.out.dcerpc_pipe, &session_key);
623 if (!NT_STATUS_IS_OK(status)) {
624 r->samr.out.error_string = talloc_asprintf(mem_ctx,
625 "dcerpc_fetch_session_key failed: %s\n",
626 nt_errstr(status));
627 goto disconnect;
630 arcfour_crypt_blob(u_info.info23.password.data, 516, &session_key);
632 sui.in.user_handle = &u_handle;
633 sui.in.info = &u_info;
634 sui.in.level = 23;
636 /* 10. try samr_SetUserInfo level 23 to set the password */
637 status = dcerpc_samr_SetUserInfo(c.pdc.out.dcerpc_pipe, mem_ctx, &sui);
638 if (!NT_STATUS_IS_OK(status)) {
639 r->samr.out.error_string = talloc_asprintf(mem_ctx,
640 "SetUserInfo level 23 for [%s] failed: %s\n",
641 r->samr.in.account_name, nt_errstr(status));
642 goto disconnect;
645 /* check result of samr_SetUserInfo level 23 */
646 if (!NT_STATUS_IS_OK(sui.out.result)) {
647 r->samr.out.error_string = talloc_asprintf(mem_ctx,
648 "SetUserInfo level 23 for [%s] failed: %s\n",
649 r->samr.in.account_name, nt_errstr(sui.out.result));
650 if (NT_STATUS_EQUAL(sui.out.result, NT_STATUS_WRONG_PASSWORD)) {
651 status = sui.out.result;
652 goto disconnect;
654 goto disconnect;
657 goto disconnect;
659 disconnect:
660 /* close connection */
661 dcerpc_pipe_close(c.pdc.out.dcerpc_pipe);
663 return status;
666 static NTSTATUS libnet_SetPassword_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
668 NTSTATUS status;
669 union libnet_SetPassword r2;
671 r2.samr.level = LIBNET_SET_PASSWORD_SAMR;
672 r2.samr.in.account_name = r->generic.in.account_name;
673 r2.samr.in.domain_name = r->generic.in.domain_name;
674 r2.samr.in.newpassword = r->generic.in.newpassword;
676 status = libnet_SetPassword(ctx, mem_ctx, &r2);
678 r->generic.out.error_string = r2.samr.out.error_string;
680 return status;
683 NTSTATUS libnet_SetPassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
685 switch (r->generic.level) {
686 case LIBNET_SET_PASSWORD_GENERIC:
687 return libnet_SetPassword_generic(ctx, mem_ctx, r);
688 case LIBNET_SET_PASSWORD_SAMR:
689 return libnet_SetPassword_samr(ctx, mem_ctx, r);
690 case LIBNET_SET_PASSWORD_KRB5:
691 return NT_STATUS_NOT_IMPLEMENTED;
692 case LIBNET_SET_PASSWORD_LDAP:
693 return NT_STATUS_NOT_IMPLEMENTED;
694 case LIBNET_SET_PASSWORD_RAP:
695 return NT_STATUS_NOT_IMPLEMENTED;
698 return NT_STATUS_INVALID_LEVEL;