2 Unix SMB/CIFS implementation.
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.
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.
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.
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/>.
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 #include "librpc/rpc/dcerpc_samr.h"
32 #include "lib/crypto/gnutls_helpers.h"
33 #include <gnutls/gnutls.h>
34 #include <gnutls/crypto.h>
36 /* User change password */
38 NTSTATUS
dcerpc_samr_chgpasswd_user(struct dcerpc_binding_handle
*h
,
40 struct policy_handle
*user_handle
,
41 const char *newpassword
,
42 const char *oldpassword
,
47 struct samr_Password hash1
, hash2
, hash3
, hash4
, hash5
, hash6
;
49 uint8_t old_nt_hash
[16] = {0};
50 uint8_t old_lm_hash
[16] = {0};
51 uint8_t new_nt_hash
[16] = {0};
52 uint8_t new_lm_hash
[16] = {0};
54 DEBUG(10,("rpccli_samr_chgpasswd_user\n"));
56 E_md4hash(oldpassword
, old_nt_hash
);
57 E_md4hash(newpassword
, new_nt_hash
);
59 E_deshash(oldpassword
, old_lm_hash
);
60 E_deshash(newpassword
, new_lm_hash
);
62 rc
= E_old_pw_hash(new_lm_hash
, old_lm_hash
, hash1
.hash
);
64 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
67 rc
= E_old_pw_hash(old_lm_hash
, new_lm_hash
, hash2
.hash
);
69 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
72 rc
= E_old_pw_hash(new_nt_hash
, old_nt_hash
, hash3
.hash
);
74 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
77 rc
= E_old_pw_hash(old_nt_hash
, new_nt_hash
, hash4
.hash
);
79 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
82 rc
= E_old_pw_hash(old_lm_hash
, new_nt_hash
, hash5
.hash
);
84 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
87 rc
= E_old_pw_hash(old_nt_hash
, new_lm_hash
, hash6
.hash
);
89 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
93 status
= dcerpc_samr_ChangePasswordUser(h
,
109 ZERO_ARRAY(old_nt_hash
);
110 ZERO_ARRAY(old_lm_hash
);
111 ZERO_ARRAY(new_nt_hash
);
112 ZERO_ARRAY(new_lm_hash
);
117 NTSTATUS
rpccli_samr_chgpasswd_user(struct rpc_pipe_client
*cli
,
119 struct policy_handle
*user_handle
,
120 const char *newpassword
,
121 const char *oldpassword
)
124 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
126 status
= dcerpc_samr_chgpasswd_user(cli
->binding_handle
,
132 if (!NT_STATUS_IS_OK(status
)) {
139 /* User change password */
141 NTSTATUS
dcerpc_samr_chgpasswd_user2(struct dcerpc_binding_handle
*h
,
143 const char *srv_name_slash
,
144 const char *username
,
145 const char *newpassword
,
146 const char *oldpassword
,
151 struct samr_CryptPassword new_nt_password
;
152 struct samr_CryptPassword new_lm_password
;
153 struct samr_Password old_nt_hash_enc
;
154 struct samr_Password old_lanman_hash_enc
;
156 uint8_t old_nt_hash
[16] = { 0 };
157 uint8_t old_lanman_hash
[16];
158 uint8_t new_nt_hash
[16];
159 uint8_t new_lanman_hash
[16];
160 struct lsa_String server
, account
;
162 DATA_BLOB session_key
= data_blob_const(old_nt_hash
, 16);
164 DEBUG(10,("rpccli_samr_chgpasswd_user2\n"));
166 init_lsa_String(&server
, srv_name_slash
);
167 init_lsa_String(&account
, username
);
169 /* Calculate the MD4 hash (NT compatible) of the password */
170 E_md4hash(oldpassword
, old_nt_hash
);
171 E_md4hash(newpassword
, new_nt_hash
);
173 if (lp_client_lanman_auth() &&
174 E_deshash(newpassword
, new_lanman_hash
) &&
175 E_deshash(oldpassword
, old_lanman_hash
)) {
176 /* E_deshash returns false for 'long' passwords (> 14
177 DOS chars). This allows us to match Win2k, which
178 does not store a LM hash for these passwords (which
179 would reduce the effective password length to 14) */
180 status
= init_samr_CryptPassword(newpassword
,
183 if (!NT_STATUS_IS_OK(status
)) {
187 rc
= E_old_pw_hash(new_nt_hash
, old_lanman_hash
, old_lanman_hash_enc
.hash
);
189 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
193 ZERO_STRUCT(new_lm_password
);
194 ZERO_STRUCT(old_lanman_hash_enc
);
197 status
= init_samr_CryptPassword(newpassword
,
200 if (!NT_STATUS_IS_OK(status
)) {
203 rc
= E_old_pw_hash(new_nt_hash
, old_nt_hash
, old_nt_hash_enc
.hash
);
205 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
209 status
= dcerpc_samr_ChangePasswordUser2(h
,
217 &old_lanman_hash_enc
,
221 ZERO_STRUCT(new_nt_password
);
222 ZERO_STRUCT(new_lm_password
);
223 ZERO_STRUCT(old_nt_hash_enc
);
224 ZERO_STRUCT(old_lanman_hash_enc
);
225 ZERO_ARRAY(new_nt_hash
);
226 ZERO_ARRAY(new_lanman_hash
);
227 ZERO_ARRAY(old_nt_hash
);
228 ZERO_ARRAY(old_lanman_hash
);
233 NTSTATUS
rpccli_samr_chgpasswd_user2(struct rpc_pipe_client
*cli
,
235 const char *username
,
236 const char *newpassword
,
237 const char *oldpassword
)
240 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
242 status
= dcerpc_samr_chgpasswd_user2(cli
->binding_handle
,
249 if (!NT_STATUS_IS_OK(status
)) {
256 /* User change password given blobs */
258 NTSTATUS
dcerpc_samr_chng_pswd_auth_crap(struct dcerpc_binding_handle
*h
,
260 const char *srv_name_slash
,
261 const char *username
,
262 DATA_BLOB new_nt_password_blob
,
263 DATA_BLOB old_nt_hash_enc_blob
,
264 DATA_BLOB new_lm_password_blob
,
265 DATA_BLOB old_lm_hash_enc_blob
,
269 struct samr_CryptPassword new_nt_password
;
270 struct samr_CryptPassword new_lm_password
;
271 struct samr_Password old_nt_hash_enc
;
272 struct samr_Password old_lm_hash_enc
;
273 struct lsa_String server
, account
;
275 DEBUG(10,("rpccli_samr_chng_pswd_auth_crap\n"));
277 ZERO_STRUCT(new_nt_password
);
278 ZERO_STRUCT(new_lm_password
);
279 ZERO_STRUCT(old_nt_hash_enc
);
280 ZERO_STRUCT(old_lm_hash_enc
);
282 init_lsa_String(&server
, srv_name_slash
);
283 init_lsa_String(&account
, username
);
285 if (new_nt_password_blob
.data
&& new_nt_password_blob
.length
>= 516) {
286 memcpy(&new_nt_password
.data
, new_nt_password_blob
.data
, 516);
289 if (new_lm_password_blob
.data
&& new_lm_password_blob
.length
>= 516) {
290 memcpy(&new_lm_password
.data
, new_lm_password_blob
.data
, 516);
293 if (old_nt_hash_enc_blob
.data
&& old_nt_hash_enc_blob
.length
>= 16) {
294 memcpy(&old_nt_hash_enc
.hash
, old_nt_hash_enc_blob
.data
, 16);
297 if (old_lm_hash_enc_blob
.data
&& old_lm_hash_enc_blob
.length
>= 16) {
298 memcpy(&old_lm_hash_enc
.hash
, old_lm_hash_enc_blob
.data
, 16);
301 status
= dcerpc_samr_ChangePasswordUser2(h
,
315 NTSTATUS
rpccli_samr_chng_pswd_auth_crap(struct rpc_pipe_client
*cli
,
317 const char *username
,
318 DATA_BLOB new_nt_password_blob
,
319 DATA_BLOB old_nt_hash_enc_blob
,
320 DATA_BLOB new_lm_password_blob
,
321 DATA_BLOB old_lm_hash_enc_blob
)
324 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
326 status
= dcerpc_samr_chng_pswd_auth_crap(cli
->binding_handle
,
330 new_nt_password_blob
,
331 old_nt_hash_enc_blob
,
332 new_lm_password_blob
,
333 old_lm_hash_enc_blob
,
335 if (!NT_STATUS_IS_OK(status
)) {
342 /* change password 3 */
344 NTSTATUS
dcerpc_samr_chgpasswd_user3(struct dcerpc_binding_handle
*h
,
346 const char *srv_name_slash
,
347 const char *username
,
348 const char *newpassword
,
349 const char *oldpassword
,
350 struct samr_DomInfo1
**dominfo1
,
351 struct userPwdChangeFailureInformation
**reject
,
357 struct samr_CryptPassword new_nt_password
;
358 struct samr_CryptPassword new_lm_password
;
359 struct samr_Password old_nt_hash_enc
;
360 struct samr_Password old_lanman_hash_enc
;
362 uint8_t old_nt_hash
[16] = { 0 };
363 uint8_t old_lanman_hash
[16];
364 uint8_t new_nt_hash
[16];
365 uint8_t new_lanman_hash
[16];
367 struct lsa_String server
, account
;
369 DATA_BLOB session_key
= data_blob_const(old_nt_hash
, 16);
371 DEBUG(10,("rpccli_samr_chgpasswd_user3\n"));
373 init_lsa_String(&server
, srv_name_slash
);
374 init_lsa_String(&account
, username
);
376 /* Calculate the MD4 hash (NT compatible) of the password */
377 E_md4hash(oldpassword
, old_nt_hash
);
378 E_md4hash(newpassword
, new_nt_hash
);
380 if (lp_client_lanman_auth() &&
381 E_deshash(newpassword
, new_lanman_hash
) &&
382 E_deshash(oldpassword
, old_lanman_hash
)) {
383 /* E_deshash returns false for 'long' passwords (> 14
384 DOS chars). This allows us to match Win2k, which
385 does not store a LM hash for these passwords (which
386 would reduce the effective password length to 14) */
387 status
= init_samr_CryptPassword(newpassword
,
390 if (!NT_STATUS_IS_OK(status
)) {
394 rc
= E_old_pw_hash(new_nt_hash
, old_lanman_hash
, old_lanman_hash_enc
.hash
);
396 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
400 ZERO_STRUCT(new_lm_password
);
401 ZERO_STRUCT(old_lanman_hash_enc
);
404 status
= init_samr_CryptPassword(newpassword
,
407 if (!NT_STATUS_IS_OK(status
)) {
411 rc
= E_old_pw_hash(new_nt_hash
, old_nt_hash
, old_nt_hash_enc
.hash
);
413 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
417 status
= dcerpc_samr_ChangePasswordUser3(h
,
425 &old_lanman_hash_enc
,
432 ZERO_STRUCT(new_nt_password
);
433 ZERO_STRUCT(new_lm_password
);
434 ZERO_STRUCT(old_nt_hash_enc
);
435 ZERO_STRUCT(old_lanman_hash_enc
);
436 ZERO_ARRAY(new_nt_hash
);
437 ZERO_ARRAY(new_lanman_hash
);
438 ZERO_ARRAY(old_nt_hash
);
439 ZERO_ARRAY(old_lanman_hash
);
444 NTSTATUS
rpccli_samr_chgpasswd_user3(struct rpc_pipe_client
*cli
,
446 const char *username
,
447 const char *newpassword
,
448 const char *oldpassword
,
449 struct samr_DomInfo1
**dominfo1
,
450 struct userPwdChangeFailureInformation
**reject
)
453 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
455 status
= dcerpc_samr_chgpasswd_user3(cli
->binding_handle
,
464 if (!NT_STATUS_IS_OK(status
)) {
471 NTSTATUS
dcerpc_samr_chgpasswd_user4(struct dcerpc_binding_handle
*h
,
473 const char *srv_name_slash
,
474 const char *username
,
475 const char *oldpassword
,
476 const char *newpassword
,
479 struct lsa_String server
, user_account
;
480 uint8_t old_nt_key_data
[16] = {0};
481 gnutls_datum_t old_nt_key
= {
482 .data
= old_nt_key_data
,
483 .size
= sizeof(old_nt_key
),
485 struct samr_EncryptedPasswordAES pwd_buf
= {
489 .data
= pwd_buf
.salt
,
490 .length
= sizeof(pwd_buf
.salt
),
492 gnutls_datum_t iv_datum
= {
496 uint8_t cek_data
[16] = {0};
499 .length
= sizeof(cek_data
),
501 uint64_t pbkdf2_iterations
= 0;
502 uint8_t pw_data
[514] = {0};
503 DATA_BLOB plaintext
= {
505 .length
= sizeof(pw_data
),
507 DATA_BLOB ciphertext
= data_blob_null
;
512 generate_nonce_buffer(iv
.data
, iv
.length
);
514 /* Calculate the MD4 hash (NT compatible) of the password */
515 E_md4hash(oldpassword
, old_nt_key_data
);
517 init_lsa_String(&server
, srv_name_slash
);
518 init_lsa_String(&user_account
, username
);
520 pbkdf2_iterations
= generate_random_u64_range(5000, 1000000);
522 rc
= gnutls_pbkdf2(GNUTLS_MAC_SHA512
,
528 BURN_DATA(old_nt_key_data
);
530 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_WRONG_PASSWORD
);
534 ok
= encode_pwd_buffer514_from_str(pw_data
, newpassword
, STR_UNICODE
);
536 return NT_STATUS_INTERNAL_ERROR
;
539 status
= samba_gnutls_aead_aes_256_cbc_hmac_sha512_encrypt(
543 &samr_aes256_enc_key_salt
,
544 &samr_aes256_mac_key_salt
,
550 if (!NT_STATUS_IS_OK(status
)) {
554 pwd_buf
.cipher_len
= ciphertext
.length
;
555 pwd_buf
.cipher
= ciphertext
.data
;
556 pwd_buf
.PBKDF2Iterations
= pbkdf2_iterations
;
558 status
= dcerpc_samr_ChangePasswordUser4(h
,
564 data_blob_free(&ciphertext
);
569 /* This function returns the bizarre set of (max_entries, max_size) required
570 for the QueryDisplayInfo RPC to actually work against a domain controller
571 with large (10k and higher) numbers of users. These values were
572 obtained by inspection using ethereal and NT4 running User Manager. */
574 void dcerpc_get_query_dispinfo_params(int loop_count
,
575 uint32_t *max_entries
,
595 default: /* loop_count >= 4 */
602 NTSTATUS
dcerpc_try_samr_connects(struct dcerpc_binding_handle
*h
,
604 const char *srv_name_slash
,
605 uint32_t access_mask
,
606 struct policy_handle
*connect_pol
,
610 union samr_ConnectInfo info_in
, info_out
;
611 struct samr_ConnectInfo1 info1
;
612 uint32_t lvl_out
= 0;
616 info1
.client_version
= SAMR_CONNECT_W2K
;
617 info_in
.info1
= info1
;
619 status
= dcerpc_samr_Connect5(h
,
629 if (NT_STATUS_IS_OK(status
) && NT_STATUS_IS_OK(*presult
)) {
633 status
= dcerpc_samr_Connect4(h
,
640 if (NT_STATUS_IS_OK(status
) && NT_STATUS_IS_OK(*presult
)) {
644 status
= dcerpc_samr_Connect2(h
,
654 /* vim: set ts=8 sw=8 noet cindent: */