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