1 /*
2    Unix SMB/CIFS implementation.
3    RPC pipe client
4    Copyright (C) Tim Potter                        2000-2001,
5    Copyright (C) Andrew Tridgell              1992-1997,2000,
6    Copyright (C) Rafal Szczesniak                       2002.
7    Copyright (C) Jeremy Allison                         2005.
8    Copyright (C) Guenther Deschner                      2008.
9 
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23 
24 #include "includes.h"
25 #include "rpc_client/rpc_client.h"
26 #include "../libcli/auth/libcli_auth.h"
27 #include "../librpc/gen_ndr/ndr_samr_c.h"
28 #include "rpc_client/cli_samr.h"
29 #include "rpc_client/init_lsa.h"
30 #include "rpc_client/init_samr.h"
31 
32 /* User change password */
33 
dcerpc_samr_chgpasswd_user(struct dcerpc_binding_handle * h,TALLOC_CTX * mem_ctx,struct policy_handle * user_handle,const char * newpassword,const char * oldpassword,NTSTATUS * presult)34 NTSTATUS dcerpc_samr_chgpasswd_user(struct dcerpc_binding_handle *h,
35 				    TALLOC_CTX *mem_ctx,
36 				    struct policy_handle *user_handle,
37 				    const char *newpassword,
38 				    const char *oldpassword,
39 				    NTSTATUS *presult)
40 {
41 	NTSTATUS status;
42 	int rc;
43 	struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
44 
45 	uint8_t old_nt_hash[16] = {0};
46 	uint8_t old_lm_hash[16] = {0};
47 	uint8_t new_nt_hash[16] = {0};
48 	uint8_t new_lm_hash[16] = {0};
49 
50 	DEBUG(10,("rpccli_samr_chgpasswd_user\n"));
51 
52 	E_md4hash(oldpassword, old_nt_hash);
53 	E_md4hash(newpassword, new_nt_hash);
54 
55 	E_deshash(oldpassword, old_lm_hash);
56 	E_deshash(newpassword, new_lm_hash);
57 
58 	rc = E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
59 	if (rc != 0) {
60 		status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
61 		goto done;
62 	}
63 	rc = E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
64 	if (rc != 0) {
65 		status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
66 		goto done;
67 	}
68 	rc = E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
69 	if (rc != 0) {
70 		status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
71 		goto done;
72 	}
73 	rc = E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
74 	if (rc != 0) {
75 		status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
76 		goto done;
77 	}
78 	rc = E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
79 	if (rc != 0) {
80 		status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
81 		goto done;
82 	}
83 	rc = E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
84 	if (rc != 0) {
85 		status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
86 		goto done;
87 	}
88 
89 	status = dcerpc_samr_ChangePasswordUser(h,
90 						mem_ctx,
91 						user_handle,
92 						true,
93 						&hash1,
94 						&hash2,
95 						true,
96 						&hash3,
97 						&hash4,
98 						true,
99 						&hash5,
100 						true,
101 						&hash6,
102 						presult);
103 
104 done:
105 	ZERO_ARRAY(old_nt_hash);
106 	ZERO_ARRAY(old_lm_hash);
107 	ZERO_ARRAY(new_nt_hash);
108 	ZERO_ARRAY(new_lm_hash);
109 
110 	return status;
111 }
112 
rpccli_samr_chgpasswd_user(struct rpc_pipe_client * cli,TALLOC_CTX * mem_ctx,struct policy_handle * user_handle,const char * newpassword,const char * oldpassword)113 NTSTATUS rpccli_samr_chgpasswd_user(struct rpc_pipe_client *cli,
114 				    TALLOC_CTX *mem_ctx,
115 				    struct policy_handle *user_handle,
116 				    const char *newpassword,
117 				    const char *oldpassword)
118 {
119 	NTSTATUS status;
120 	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
121 
122 	status = dcerpc_samr_chgpasswd_user(cli->binding_handle,
123 					    mem_ctx,
124 					    user_handle,
125 					    newpassword,
126 					    oldpassword,
127 					    &result);
128 	if (!NT_STATUS_IS_OK(status)) {
129 		return status;
130 	}
131 
132 	return result;
133 }
134 
135 /* User change password */
136 
dcerpc_samr_chgpasswd_user2(struct dcerpc_binding_handle * h,TALLOC_CTX * mem_ctx,const char * srv_name_slash,const char * username,const char * newpassword,const char * oldpassword,NTSTATUS * presult)137 NTSTATUS dcerpc_samr_chgpasswd_user2(struct dcerpc_binding_handle *h,
138 				     TALLOC_CTX *mem_ctx,
139 				     const char *srv_name_slash,
140 				     const char *username,
141 				     const char *newpassword,
142 				     const char *oldpassword,
143 				     NTSTATUS *presult)
144 {
145 	NTSTATUS status;
146 	int rc;
147 	struct samr_CryptPassword new_nt_password;
148 	struct samr_CryptPassword new_lm_password;
149 	struct samr_Password old_nt_hash_enc;
150 	struct samr_Password old_lanman_hash_enc;
151 
152 	uint8_t old_nt_hash[16];
153 	uint8_t old_lanman_hash[16];
154 	uint8_t new_nt_hash[16];
155 	uint8_t new_lanman_hash[16];
156 	struct lsa_String server, account;
157 
158 	DATA_BLOB session_key = data_blob_const(old_nt_hash, 16);
159 
160 	DEBUG(10,("rpccli_samr_chgpasswd_user2\n"));
161 
162 	init_lsa_String(&server, srv_name_slash);
163 	init_lsa_String(&account, username);
164 
165 	/* Calculate the MD4 hash (NT compatible) of the password */
166 	E_md4hash(oldpassword, old_nt_hash);
167 	E_md4hash(newpassword, new_nt_hash);
168 
169 	if (lp_client_lanman_auth() &&
170 	    E_deshash(newpassword, new_lanman_hash) &&
171 	    E_deshash(oldpassword, old_lanman_hash)) {
172 		/* E_deshash returns false for 'long' passwords (> 14
173 		   DOS chars).  This allows us to match Win2k, which
174 		   does not store a LM hash for these passwords (which
175 		   would reduce the effective password length to 14) */
176 		status = init_samr_CryptPassword(newpassword,
177 						 &session_key,
178 						 &new_lm_password);
179 		if (!NT_STATUS_IS_OK(status)) {
180 			return status;
181 		}
182 
183 		rc = E_old_pw_hash(new_nt_hash, old_lanman_hash, old_lanman_hash_enc.hash);
184 		if (rc != 0) {
185 			status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
186 			goto done;
187 		}
188 	} else {
189 		ZERO_STRUCT(new_lm_password);
190 		ZERO_STRUCT(old_lanman_hash_enc);
191 	}
192 
193 	status = init_samr_CryptPassword(newpassword,
194 					 &session_key,
195 					 &new_nt_password);
196 	if (!NT_STATUS_IS_OK(status)) {
197 		return status;
198 	}
199 	rc = E_old_pw_hash(new_nt_hash, old_nt_hash, old_nt_hash_enc.hash);
200 	if (rc != 0) {
201 		status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
202 		goto done;
203 	}
204 
205 	status = dcerpc_samr_ChangePasswordUser2(h,
206 						 mem_ctx,
207 						 &server,
208 						 &account,
209 						 &new_nt_password,
210 						 &old_nt_hash_enc,
211 						 true,
212 						 &new_lm_password,
213 						 &old_lanman_hash_enc,
214 						 presult);
215 
216 done:
217 	ZERO_STRUCT(new_nt_password);
218 	ZERO_STRUCT(new_lm_password);
219 	ZERO_STRUCT(old_nt_hash_enc);
220 	ZERO_STRUCT(old_lanman_hash_enc);
221 	ZERO_ARRAY(new_nt_hash);
222 	ZERO_ARRAY(new_lanman_hash);
223 	ZERO_ARRAY(old_nt_hash);
224 	ZERO_ARRAY(old_lanman_hash);
225 
226 	return status;
227 }
228 
rpccli_samr_chgpasswd_user2(struct rpc_pipe_client * cli,TALLOC_CTX * mem_ctx,const char * username,const char * newpassword,const char * oldpassword)229 NTSTATUS rpccli_samr_chgpasswd_user2(struct rpc_pipe_client *cli,
230 				     TALLOC_CTX *mem_ctx,
231 				     const char *username,
232 				     const char *newpassword,
233 				     const char *oldpassword)
234 {
235 	NTSTATUS status;
236 	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
237 
238 	status = dcerpc_samr_chgpasswd_user2(cli->binding_handle,
239 					     mem_ctx,
240 					     cli->srv_name_slash,
241 					     username,
242 					     newpassword,
243 					     oldpassword,
244 					     &result);
245 	if (!NT_STATUS_IS_OK(status)) {
246 		return status;
247 	}
248 
249 	return result;
250 }
251 
252 /* User change password given blobs */
253 
dcerpc_samr_chng_pswd_auth_crap(struct dcerpc_binding_handle * h,TALLOC_CTX * mem_ctx,const char * srv_name_slash,const char * username,DATA_BLOB new_nt_password_blob,DATA_BLOB old_nt_hash_enc_blob,DATA_BLOB new_lm_password_blob,DATA_BLOB old_lm_hash_enc_blob,NTSTATUS * presult)254 NTSTATUS dcerpc_samr_chng_pswd_auth_crap(struct dcerpc_binding_handle *h,
255 					 TALLOC_CTX *mem_ctx,
256 					 const char *srv_name_slash,
257 					 const char *username,
258 					 DATA_BLOB new_nt_password_blob,
259 					 DATA_BLOB old_nt_hash_enc_blob,
260 					 DATA_BLOB new_lm_password_blob,
261 					 DATA_BLOB old_lm_hash_enc_blob,
262 					 NTSTATUS *presult)
263 {
264 	NTSTATUS status;
265 	struct samr_CryptPassword new_nt_password;
266 	struct samr_CryptPassword new_lm_password;
267 	struct samr_Password old_nt_hash_enc;
268 	struct samr_Password old_lm_hash_enc;
269 	struct lsa_String server, account;
270 
271 	DEBUG(10,("rpccli_samr_chng_pswd_auth_crap\n"));
272 
273 	ZERO_STRUCT(new_nt_password);
274 	ZERO_STRUCT(new_lm_password);
275 	ZERO_STRUCT(old_nt_hash_enc);
276 	ZERO_STRUCT(old_lm_hash_enc);
277 
278 	init_lsa_String(&server, srv_name_slash);
279 	init_lsa_String(&account, username);
280 
281 	if (new_nt_password_blob.data && new_nt_password_blob.length >= 516) {
282 		memcpy(&new_nt_password.data, new_nt_password_blob.data, 516);
283 	}
284 
285 	if (new_lm_password_blob.data && new_lm_password_blob.length >= 516) {
286 		memcpy(&new_lm_password.data, new_lm_password_blob.data, 516);
287 	}
288 
289 	if (old_nt_hash_enc_blob.data && old_nt_hash_enc_blob.length >= 16) {
290 		memcpy(&old_nt_hash_enc.hash, old_nt_hash_enc_blob.data, 16);
291 	}
292 
293 	if (old_lm_hash_enc_blob.data && old_lm_hash_enc_blob.length >= 16) {
294 		memcpy(&old_lm_hash_enc.hash, old_lm_hash_enc_blob.data, 16);
295 	}
296 
297 	status = dcerpc_samr_ChangePasswordUser2(h,
298 						 mem_ctx,
299 						 &server,
300 						 &account,
301 						 &new_nt_password,
302 						 &old_nt_hash_enc,
303 						 true,
304 						 &new_lm_password,
305 						 &old_lm_hash_enc,
306 						 presult);
307 
308 	return status;
309 }
310 
rpccli_samr_chng_pswd_auth_crap(struct rpc_pipe_client * cli,TALLOC_CTX * mem_ctx,const char * username,DATA_BLOB new_nt_password_blob,DATA_BLOB old_nt_hash_enc_blob,DATA_BLOB new_lm_password_blob,DATA_BLOB old_lm_hash_enc_blob)311 NTSTATUS rpccli_samr_chng_pswd_auth_crap(struct rpc_pipe_client *cli,
312 					 TALLOC_CTX *mem_ctx,
313 					 const char *username,
314 					 DATA_BLOB new_nt_password_blob,
315 					 DATA_BLOB old_nt_hash_enc_blob,
316 					 DATA_BLOB new_lm_password_blob,
317 					 DATA_BLOB old_lm_hash_enc_blob)
318 {
319 	NTSTATUS status;
320 	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
321 
322 	status = dcerpc_samr_chng_pswd_auth_crap(cli->binding_handle,
323 						 mem_ctx,
324 						 cli->srv_name_slash,
325 						 username,
326 						 new_nt_password_blob,
327 						 old_nt_hash_enc_blob,
328 						 new_lm_password_blob,
329 						 old_lm_hash_enc_blob,
330 						 &result);
331 	if (!NT_STATUS_IS_OK(status)) {
332 		return status;
333 	}
334 
335 	return result;
336 }
337 
338 /* change password 3 */
339 
dcerpc_samr_chgpasswd_user3(struct dcerpc_binding_handle * h,TALLOC_CTX * mem_ctx,const char * srv_name_slash,const char * username,const char * newpassword,const char * oldpassword,struct samr_DomInfo1 ** dominfo1,struct userPwdChangeFailureInformation ** reject,NTSTATUS * presult)340 NTSTATUS dcerpc_samr_chgpasswd_user3(struct dcerpc_binding_handle *h,
341 				     TALLOC_CTX *mem_ctx,
342 				     const char *srv_name_slash,
343 				     const char *username,
344 				     const char *newpassword,
345 				     const char *oldpassword,
346 				     struct samr_DomInfo1 **dominfo1,
347 				     struct userPwdChangeFailureInformation **reject,
348 				     NTSTATUS *presult)
349 {
350 	NTSTATUS status;
351 	int rc;
352 
353 	struct samr_CryptPassword new_nt_password;
354 	struct samr_CryptPassword new_lm_password;
355 	struct samr_Password old_nt_hash_enc;
356 	struct samr_Password old_lanman_hash_enc;
357 
358 	uint8_t old_nt_hash[16];
359 	uint8_t old_lanman_hash[16];
360 	uint8_t new_nt_hash[16];
361 	uint8_t new_lanman_hash[16];
362 
363 	struct lsa_String server, account;
364 
365 	DATA_BLOB session_key = data_blob_const(old_nt_hash, 16);
366 
367 	DEBUG(10,("rpccli_samr_chgpasswd_user3\n"));
368 
369 	init_lsa_String(&server, srv_name_slash);
370 	init_lsa_String(&account, username);
371 
372 	/* Calculate the MD4 hash (NT compatible) of the password */
373 	E_md4hash(oldpassword, old_nt_hash);
374 	E_md4hash(newpassword, new_nt_hash);
375 
376 	if (lp_client_lanman_auth() &&
377 	    E_deshash(newpassword, new_lanman_hash) &&
378 	    E_deshash(oldpassword, old_lanman_hash)) {
379 		/* E_deshash returns false for 'long' passwords (> 14
380 		   DOS chars).  This allows us to match Win2k, which
381 		   does not store a LM hash for these passwords (which
382 		   would reduce the effective password length to 14) */
383 		status = init_samr_CryptPassword(newpassword,
384 						 &session_key,
385 						 &new_lm_password);
386 		if (!NT_STATUS_IS_OK(status)) {
387 			return status;
388 		}
389 
390 		rc = E_old_pw_hash(new_nt_hash, old_lanman_hash, old_lanman_hash_enc.hash);
391 		if (rc != 0) {
392 			status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
393 			goto done;
394 		}
395 	} else {
396 		ZERO_STRUCT(new_lm_password);
397 		ZERO_STRUCT(old_lanman_hash_enc);
398 	}
399 
400 	status = init_samr_CryptPassword(newpassword,
401 					 &session_key,
402 					 &new_nt_password);
403 	if (!NT_STATUS_IS_OK(status)) {
404 		return status;
405 	}
406 
407 	rc = E_old_pw_hash(new_nt_hash, old_nt_hash, old_nt_hash_enc.hash);
408 	if (rc != 0) {
409 		status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
410 		goto done;
411 	}
412 
413 	status = dcerpc_samr_ChangePasswordUser3(h,
414 						 mem_ctx,
415 						 &server,
416 						 &account,
417 						 &new_nt_password,
418 						 &old_nt_hash_enc,
419 						 true,
420 						 &new_lm_password,
421 						 &old_lanman_hash_enc,
422 						 NULL,
423 						 dominfo1,
424 						 reject,
425 						 presult);
426 
427 done:
428 	ZERO_STRUCT(new_nt_password);
429 	ZERO_STRUCT(new_lm_password);
430 	ZERO_STRUCT(old_nt_hash_enc);
431 	ZERO_STRUCT(old_lanman_hash_enc);
432 	ZERO_ARRAY(new_nt_hash);
433 	ZERO_ARRAY(new_lanman_hash);
434 	ZERO_ARRAY(old_nt_hash);
435 	ZERO_ARRAY(old_lanman_hash);
436 
437 	return status;
438 }
439 
rpccli_samr_chgpasswd_user3(struct rpc_pipe_client * cli,TALLOC_CTX * mem_ctx,const char * username,const char * newpassword,const char * oldpassword,struct samr_DomInfo1 ** dominfo1,struct userPwdChangeFailureInformation ** reject)440 NTSTATUS rpccli_samr_chgpasswd_user3(struct rpc_pipe_client *cli,
441 				     TALLOC_CTX *mem_ctx,
442 				     const char *username,
443 				     const char *newpassword,
444 				     const char *oldpassword,
445 				     struct samr_DomInfo1 **dominfo1,
446 				     struct userPwdChangeFailureInformation **reject)
447 {
448 	NTSTATUS status;
449 	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
450 
451 	status = dcerpc_samr_chgpasswd_user3(cli->binding_handle,
452 					     mem_ctx,
453 					     cli->srv_name_slash,
454 					     username,
455 					     newpassword,
456 					     oldpassword,
457 					     dominfo1,
458 					     reject,
459 					     &result);
460 	if (!NT_STATUS_IS_OK(status)) {
461 		return status;
462 	}
463 
464 	return result;
465 }
466 
467 /* This function returns the bizzare set of (max_entries, max_size) required
468    for the QueryDisplayInfo RPC to actually work against a domain controller
469    with large (10k and higher) numbers of users.  These values were
470    obtained by inspection using ethereal and NT4 running User Manager. */
471 
dcerpc_get_query_dispinfo_params(int loop_count,uint32_t * max_entries,uint32_t * max_size)472 void dcerpc_get_query_dispinfo_params(int loop_count,
473 				      uint32_t *max_entries,
474 				      uint32_t *max_size)
475 {
476 	switch(loop_count) {
477 	case 0:
478 		*max_entries = 512;
479 		*max_size = 16383;
480 		break;
481 	case 1:
482 		*max_entries = 1024;
483 		*max_size = 32766;
484 		break;
485 	case 2:
486 		*max_entries = 2048;
487 		*max_size = 65532;
488 		break;
489 	case 3:
490 		*max_entries = 4096;
491 		*max_size = 131064;
492 		break;
493 	default:              /* loop_count >= 4 */
494 		*max_entries = 4096;
495 		*max_size = 131071;
496 		break;
497 	}
498 }
499 
dcerpc_try_samr_connects(struct dcerpc_binding_handle * h,TALLOC_CTX * mem_ctx,const char * srv_name_slash,uint32_t access_mask,struct policy_handle * connect_pol,NTSTATUS * presult)500 NTSTATUS dcerpc_try_samr_connects(struct dcerpc_binding_handle *h,
501 				  TALLOC_CTX *mem_ctx,
502 				  const char *srv_name_slash,
503 				  uint32_t access_mask,
504 				  struct policy_handle *connect_pol,
505 				  NTSTATUS *presult)
506 {
507 	NTSTATUS status;
508 	union samr_ConnectInfo info_in, info_out;
509 	struct samr_ConnectInfo1 info1;
510 	uint32_t lvl_out = 0;
511 
512 	ZERO_STRUCT(info1);
513 
514 	info1.client_version = SAMR_CONNECT_W2K;
515 	info_in.info1 = info1;
516 
517 	status = dcerpc_samr_Connect5(h,
518 				      mem_ctx,
519 				      srv_name_slash,
520 				      access_mask,
521 				      1,
522 				      &info_in,
523 				      &lvl_out,
524 				      &info_out,
525 				      connect_pol,
526 				      presult);
527 	if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(*presult)) {
528 		return status;
529 	}
530 
531 	status = dcerpc_samr_Connect4(h,
532 				      mem_ctx,
533 				      srv_name_slash,
534 				      SAMR_CONNECT_W2K,
535 				      access_mask,
536 				      connect_pol,
537 				      presult);
538 	if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(*presult)) {
539 		return status;
540 	}
541 
542 	status = dcerpc_samr_Connect2(h,
543 				      mem_ctx,
544 				      srv_name_slash,
545 				      access_mask,
546 				      connect_pol,
547 				      presult);
548 
549 	return status;
550 }
551 
552 /* vim: set ts=8 sw=8 noet cindent: */
553