2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2004
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
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.
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.
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/>.
22 #include "libnet/libnet.h"
23 #include "libcli/auth/libcli_auth.h"
24 #include "librpc/gen_ndr/ndr_samr_c.h"
25 #include "source4/librpc/rpc/dcerpc.h"
26 #include "auth/credentials/credentials.h"
27 #include "libcli/smb/smb_constants.h"
28 #include "librpc/rpc/dcerpc_samr.h"
29 #include "source3/rpc_client/init_samr.h"
30 #include "lib/param/loadparm.h"
31 #include "lib/param/param.h"
33 #include "lib/crypto/gnutls_helpers.h"
34 #include <gnutls/gnutls.h>
35 #include <gnutls/crypto.h>
37 static NTSTATUS
libnet_ChangePassword_samr_aes(TALLOC_CTX
*mem_ctx
,
38 struct dcerpc_binding_handle
*h
,
39 struct lsa_String
*server
,
40 struct lsa_String
*account
,
41 const char *old_password
,
42 const char *new_password
,
43 const char **error_string
)
45 #ifdef HAVE_GNUTLS_PBKDF2
46 struct samr_ChangePasswordUser4 r
;
47 uint8_t old_nt_key_data
[16] = {0};
48 gnutls_datum_t old_nt_key
= {
49 .data
= old_nt_key_data
,
50 .size
= sizeof(old_nt_key_data
),
52 uint8_t cek_data
[16] = {0};
55 .length
= sizeof(cek_data
),
57 struct samr_EncryptedPasswordAES pwd_buf
= {
62 .length
= sizeof(pwd_buf
.salt
),
64 gnutls_datum_t salt_datum
= {
66 .size
= sizeof(pwd_buf
.salt
),
68 uint64_t pbkdf2_iterations
= generate_random_u64_range(5000, 1000000);
72 E_md4hash(old_password
, old_nt_key_data
);
74 generate_nonce_buffer(salt
.data
, salt
.length
);
76 rc
= gnutls_pbkdf2(GNUTLS_MAC_SHA512
,
82 BURN_DATA(old_nt_key_data
);
84 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_WRONG_PASSWORD
);
87 status
= init_samr_CryptPasswordAES(mem_ctx
,
92 data_blob_clear(&cek
);
93 if (!NT_STATUS_IS_OK(status
)) {
97 pwd_buf
.PBKDF2Iterations
= pbkdf2_iterations
;
100 r
.in
.account
= account
;
101 r
.in
.password
= &pwd_buf
;
103 status
= dcerpc_samr_ChangePasswordUser4_r(h
, mem_ctx
, &r
);
104 if (!NT_STATUS_IS_OK(status
)) {
107 if (!NT_STATUS_IS_OK(r
.out
.result
)) {
108 *error_string
= talloc_asprintf(mem_ctx
,
109 "samr_ChangePasswordUser4 for "
110 "'%s\\%s' failed: %s",
114 status
= r
.out
.result
;
122 #else /* HAVE_GNUTLS_PBKDF2 */
123 return NT_STATUS_NOT_IMPLEMENTED
;
124 #endif /* HAVE_GNUTLS_PBKDF2 */
127 static NTSTATUS
libnet_ChangePassword_samr_rc4(TALLOC_CTX
*mem_ctx
,
128 struct dcerpc_binding_handle
*h
,
129 struct lsa_String
*server
,
130 struct lsa_String
*account
,
131 const char *old_password
,
132 const char *new_password
,
133 const char **error_string
)
135 struct samr_OemChangePasswordUser2 oe2
;
136 struct samr_ChangePasswordUser2 pw2
;
137 struct samr_ChangePasswordUser3 pw3
;
138 struct samr_CryptPassword nt_pass
, lm_pass
;
139 uint8_t old_nt_hash
[16], new_nt_hash
[16];
140 uint8_t old_lm_hash
[16], new_lm_hash
[16];
141 struct samr_Password nt_verifier
, lm_verifier
;
142 struct lsa_AsciiString a_server
, a_account
;
143 gnutls_cipher_hd_t cipher_hnd
= NULL
;
144 gnutls_datum_t nt_session_key
= {
146 .size
= sizeof(old_nt_hash
),
148 gnutls_datum_t lm_session_key
= {
150 .size
= sizeof(old_lm_hash
),
152 struct samr_DomInfo1
*dominfo
= NULL
;
153 struct userPwdChangeFailureInformation
*reject
= NULL
;
157 E_md4hash(old_password
, old_nt_hash
);
158 E_md4hash(new_password
, new_nt_hash
);
160 E_deshash(old_password
, old_lm_hash
);
161 E_deshash(new_password
, new_lm_hash
);
163 /* prepare samr_ChangePasswordUser3 */
164 encode_pw_buffer(lm_pass
.data
, new_password
, STR_UNICODE
);
166 rc
= gnutls_cipher_init(&cipher_hnd
,
167 GNUTLS_CIPHER_ARCFOUR_128
,
171 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
175 rc
= gnutls_cipher_encrypt(cipher_hnd
,
178 gnutls_cipher_deinit(cipher_hnd
);
180 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
184 rc
= E_old_pw_hash(new_lm_hash
, old_lm_hash
, lm_verifier
.hash
);
186 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
190 encode_pw_buffer(nt_pass
.data
, new_password
, STR_UNICODE
);
192 rc
= gnutls_cipher_init(&cipher_hnd
,
193 GNUTLS_CIPHER_ARCFOUR_128
,
197 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
201 rc
= gnutls_cipher_encrypt(cipher_hnd
,
204 gnutls_cipher_deinit(cipher_hnd
);
206 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
210 rc
= E_old_pw_hash(new_nt_hash
, old_nt_hash
, nt_verifier
.hash
);
212 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
216 pw3
.in
.server
= server
;
217 pw3
.in
.account
= account
;
218 pw3
.in
.nt_password
= &nt_pass
;
219 pw3
.in
.nt_verifier
= &nt_verifier
;
220 pw3
.in
.lm_change
= 1;
221 pw3
.in
.lm_password
= &lm_pass
;
222 pw3
.in
.lm_verifier
= &lm_verifier
;
223 pw3
.in
.password3
= NULL
;
224 pw3
.out
.dominfo
= &dominfo
;
225 pw3
.out
.reject
= &reject
;
227 /* 2. try samr_ChangePasswordUser3 */
228 status
= dcerpc_samr_ChangePasswordUser3_r(h
, mem_ctx
, &pw3
);
229 if (!NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
230 if (NT_STATUS_IS_OK(status
) && !NT_STATUS_IS_OK(pw3
.out
.result
)) {
231 status
= pw3
.out
.result
;
233 if (!NT_STATUS_IS_OK(status
)) {
234 *error_string
= talloc_asprintf(
236 "samr_ChangePasswordUser3 failed: %s",
239 talloc_asprintf(mem_ctx
,
240 "samr_ChangePasswordUser3 for "
241 "'%s\\%s' failed: %s",
249 /* prepare samr_ChangePasswordUser2 */
250 encode_pw_buffer(lm_pass
.data
, new_password
, STR_ASCII
| STR_TERMINATE
);
252 rc
= gnutls_cipher_init(&cipher_hnd
,
253 GNUTLS_CIPHER_ARCFOUR_128
,
257 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
261 rc
= gnutls_cipher_encrypt(cipher_hnd
,
264 gnutls_cipher_deinit(cipher_hnd
);
266 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
270 rc
= E_old_pw_hash(new_lm_hash
, old_lm_hash
, lm_verifier
.hash
);
272 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
276 encode_pw_buffer(nt_pass
.data
, new_password
, STR_UNICODE
);
278 rc
= gnutls_cipher_init(&cipher_hnd
,
279 GNUTLS_CIPHER_ARCFOUR_128
,
283 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
286 rc
= gnutls_cipher_encrypt(cipher_hnd
,
289 gnutls_cipher_deinit(cipher_hnd
);
291 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
295 rc
= E_old_pw_hash(new_nt_hash
, old_nt_hash
, nt_verifier
.hash
);
297 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
301 pw2
.in
.server
= server
;
302 pw2
.in
.account
= account
;
303 pw2
.in
.nt_password
= &nt_pass
;
304 pw2
.in
.nt_verifier
= &nt_verifier
;
305 pw2
.in
.lm_change
= 1;
306 pw2
.in
.lm_password
= &lm_pass
;
307 pw2
.in
.lm_verifier
= &lm_verifier
;
309 /* 3. try samr_ChangePasswordUser2 */
310 status
= dcerpc_samr_ChangePasswordUser2_r(h
, mem_ctx
, &pw2
);
311 if (!NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
312 if (NT_STATUS_IS_OK(status
) && !NT_STATUS_IS_OK(pw2
.out
.result
)) {
313 status
= pw2
.out
.result
;
315 if (!NT_STATUS_IS_OK(status
)) {
317 talloc_asprintf(mem_ctx
,
318 "samr_ChangePasswordUser2 for "
319 "'%s\\%s' failed: %s",
328 /* prepare samr_OemChangePasswordUser2 */
329 a_server
.string
= server
->string
;
330 a_account
.string
= account
->string
;
332 encode_pw_buffer(lm_pass
.data
, new_password
, STR_ASCII
);
334 rc
= gnutls_cipher_init(&cipher_hnd
,
335 GNUTLS_CIPHER_ARCFOUR_128
,
339 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
343 rc
= gnutls_cipher_encrypt(cipher_hnd
,
346 gnutls_cipher_deinit(cipher_hnd
);
348 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
352 rc
= E_old_pw_hash(new_lm_hash
, old_lm_hash
, lm_verifier
.hash
);
354 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
358 oe2
.in
.server
= &a_server
;
359 oe2
.in
.account
= &a_account
;
360 oe2
.in
.password
= &lm_pass
;
361 oe2
.in
.hash
= &lm_verifier
;
363 /* 4. try samr_OemChangePasswordUser2 */
364 status
= dcerpc_samr_OemChangePasswordUser2_r(h
, mem_ctx
, &oe2
);
365 if (!NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
366 if (NT_STATUS_IS_OK(status
) && !NT_STATUS_IS_OK(oe2
.out
.result
)) {
367 status
= oe2
.out
.result
;
369 if (!NT_STATUS_IS_OK(oe2
.out
.result
)) {
371 talloc_asprintf(mem_ctx
,
372 "samr_OemChangePasswordUser2 "
373 "for '%s\\%s' failed: %s",
381 status
= NT_STATUS_OK
;
387 * do a password change using DCERPC/SAMR calls
388 * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
389 * 2. try samr_ChangePasswordUser3
390 * 3. try samr_ChangePasswordUser2
391 * 4. try samr_OemChangePasswordUser2
393 static NTSTATUS
libnet_ChangePassword_samr(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, union libnet_ChangePassword
*r
)
396 struct libnet_RpcConnect c
;
397 struct lsa_String server
, account
;
401 /* prepare connect to the SAMR pipe of the users domain PDC */
402 c
.level
= LIBNET_RPC_CONNECT_PDC
;
403 c
.in
.name
= r
->samr
.in
.domain_name
;
404 c
.in
.dcerpc_iface
= &ndr_table_samr
;
405 c
.in
.dcerpc_flags
= DCERPC_ANON_FALLBACK
;
407 /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
408 status
= libnet_RpcConnect(ctx
, mem_ctx
, &c
);
409 if (!NT_STATUS_IS_OK(status
)) {
410 r
->samr
.out
.error_string
= talloc_asprintf(mem_ctx
,
411 "Connection to SAMR pipe of PDC of domain '%s' failed: %s",
412 r
->samr
.in
.domain_name
, nt_errstr(status
));
416 /* prepare password change for account */
417 server
.string
= talloc_asprintf(mem_ctx
, "\\\\%s", dcerpc_server_name(c
.out
.dcerpc_pipe
));
418 account
.string
= r
->samr
.in
.account_name
;
420 status
= libnet_ChangePassword_samr_aes(
422 c
.out
.dcerpc_pipe
->binding_handle
,
425 r
->samr
.in
.oldpassword
,
426 r
->samr
.in
.newpassword
,
427 &(r
->samr
.out
.error_string
));
428 if (NT_STATUS_IS_OK(status
)) {
430 } else if (NT_STATUS_EQUAL(status
,
431 NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
) ||
432 NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
) ||
433 NT_STATUS_EQUAL(status
, NT_STATUS_NOT_IMPLEMENTED
)) {
435 * Don't fallback to RC4 based SAMR if weak crypto is not
438 if (lpcfg_weak_crypto(ctx
->lp_ctx
) ==
439 SAMBA_WEAK_CRYPTO_DISALLOWED
) {
443 /* libnet_ChangePassword_samr_aes is implemented and failed */
447 status
= libnet_ChangePassword_samr_rc4(
449 c
.out
.dcerpc_pipe
->binding_handle
,
452 r
->samr
.in
.oldpassword
,
453 r
->samr
.in
.newpassword
,
454 &(r
->samr
.out
.error_string
));
455 if (!NT_STATUS_IS_OK(status
)) {
460 /* close connection */
461 talloc_unlink(ctx
, c
.out
.dcerpc_pipe
);
466 static NTSTATUS
libnet_ChangePassword_generic(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, union libnet_ChangePassword
*r
)
469 union libnet_ChangePassword r2
;
471 r2
.samr
.level
= LIBNET_CHANGE_PASSWORD_SAMR
;
472 r2
.samr
.in
.account_name
= r
->generic
.in
.account_name
;
473 r2
.samr
.in
.domain_name
= r
->generic
.in
.domain_name
;
474 r2
.samr
.in
.oldpassword
= r
->generic
.in
.oldpassword
;
475 r2
.samr
.in
.newpassword
= r
->generic
.in
.newpassword
;
477 status
= libnet_ChangePassword(ctx
, mem_ctx
, &r2
);
479 r
->generic
.out
.error_string
= r2
.samr
.out
.error_string
;
484 NTSTATUS
libnet_ChangePassword(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, union libnet_ChangePassword
*r
)
486 switch (r
->generic
.level
) {
487 case LIBNET_CHANGE_PASSWORD_GENERIC
:
488 return libnet_ChangePassword_generic(ctx
, mem_ctx
, r
);
489 case LIBNET_CHANGE_PASSWORD_SAMR
:
490 return libnet_ChangePassword_samr(ctx
, mem_ctx
, r
);
491 case LIBNET_CHANGE_PASSWORD_KRB5
:
492 return NT_STATUS_NOT_IMPLEMENTED
;
493 case LIBNET_CHANGE_PASSWORD_LDAP
:
494 return NT_STATUS_NOT_IMPLEMENTED
;
495 case LIBNET_CHANGE_PASSWORD_RAP
:
496 return NT_STATUS_NOT_IMPLEMENTED
;
499 return NT_STATUS_INVALID_LEVEL
;
502 static NTSTATUS
libnet_SetPassword_samr_handle_26(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, union libnet_SetPassword
*r
)
505 struct samr_SetUserInfo2 sui
;
506 union samr_UserInfo u_info
;
507 DATA_BLOB session_key
;
509 if (r
->samr_handle
.in
.info21
) {
510 return NT_STATUS_INVALID_PARAMETER_MIX
;
513 /* prepare samr_SetUserInfo2 level 26 */
515 u_info
.info26
.password_expired
= 0;
517 status
= dcerpc_fetch_session_key(r
->samr_handle
.in
.dcerpc_pipe
, &session_key
);
518 if (!NT_STATUS_IS_OK(status
)) {
519 r
->samr_handle
.out
.error_string
= talloc_asprintf(mem_ctx
,
520 "dcerpc_fetch_session_key failed: %s",
525 status
= encode_rc4_passwd_buffer(r
->samr_handle
.in
.newpassword
,
527 &u_info
.info26
.password
);
528 if (!NT_STATUS_IS_OK(status
)) {
529 r
->samr_handle
.out
.error_string
=
530 talloc_asprintf(mem_ctx
,
531 "encode_rc4_passwd_buffer failed: %s",
536 sui
.in
.user_handle
= r
->samr_handle
.in
.user_handle
;
537 sui
.in
.info
= &u_info
;
540 /* 7. try samr_SetUserInfo2 level 26 to set the password */
541 status
= dcerpc_samr_SetUserInfo2_r(r
->samr_handle
.in
.dcerpc_pipe
->binding_handle
, mem_ctx
, &sui
);
542 /* check result of samr_SetUserInfo2 level 26 */
543 if (NT_STATUS_IS_OK(status
) && !NT_STATUS_IS_OK(sui
.out
.result
)) {
544 status
= sui
.out
.result
;
546 if (!NT_STATUS_IS_OK(status
)) {
547 r
->samr_handle
.out
.error_string
548 = talloc_asprintf(mem_ctx
,
549 "SetUserInfo2 level 26 for [%s] failed: %s",
550 r
->samr_handle
.in
.account_name
, nt_errstr(status
));
556 static NTSTATUS
libnet_SetPassword_samr_handle_25(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, union libnet_SetPassword
*r
)
559 struct samr_SetUserInfo2 sui
;
560 union samr_UserInfo u_info
;
561 DATA_BLOB session_key
;
563 if (!r
->samr_handle
.in
.info21
) {
564 return NT_STATUS_INVALID_PARAMETER_MIX
;
567 /* prepare samr_SetUserInfo2 level 25 */
569 u_info
.info25
.info
= *r
->samr_handle
.in
.info21
;
570 u_info
.info25
.info
.fields_present
|= SAMR_FIELD_NT_PASSWORD_PRESENT
;
572 status
= dcerpc_fetch_session_key(r
->samr_handle
.in
.dcerpc_pipe
, &session_key
);
573 if (!NT_STATUS_IS_OK(status
)) {
574 r
->samr_handle
.out
.error_string
= talloc_asprintf(mem_ctx
,
575 "dcerpc_fetch_session_key failed: %s",
580 status
= encode_rc4_passwd_buffer(r
->samr_handle
.in
.newpassword
,
582 &u_info
.info25
.password
);
583 if (!NT_STATUS_IS_OK(status
)) {
584 r
->samr_handle
.out
.error_string
=
585 talloc_asprintf(mem_ctx
,
586 "encode_rc4_passwd_buffer failed: %s",
592 sui
.in
.user_handle
= r
->samr_handle
.in
.user_handle
;
593 sui
.in
.info
= &u_info
;
596 /* 8. try samr_SetUserInfo2 level 25 to set the password */
597 status
= dcerpc_samr_SetUserInfo2_r(r
->samr_handle
.in
.dcerpc_pipe
->binding_handle
, mem_ctx
, &sui
);
598 if (NT_STATUS_IS_OK(status
) && !NT_STATUS_IS_OK(sui
.out
.result
)) {
599 status
= sui
.out
.result
;
601 if (!NT_STATUS_IS_OK(status
)) {
602 r
->samr_handle
.out
.error_string
603 = talloc_asprintf(mem_ctx
,
604 "SetUserInfo2 level 25 for [%s] failed: %s",
605 r
->samr_handle
.in
.account_name
, nt_errstr(status
));
611 static NTSTATUS
libnet_SetPassword_samr_handle_24(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, union libnet_SetPassword
*r
)
614 struct samr_SetUserInfo2 sui
;
615 union samr_UserInfo u_info
;
616 DATA_BLOB session_key
;
617 gnutls_cipher_hd_t cipher_hnd
= NULL
;
618 gnutls_datum_t enc_session_key
;
621 if (r
->samr_handle
.in
.info21
) {
622 return NT_STATUS_INVALID_PARAMETER_MIX
;
625 /* prepare samr_SetUserInfo2 level 24 */
627 encode_pw_buffer(u_info
.info24
.password
.data
, r
->samr_handle
.in
.newpassword
, STR_UNICODE
);
628 u_info
.info24
.password_expired
= 0;
630 status
= dcerpc_fetch_session_key(r
->samr_handle
.in
.dcerpc_pipe
, &session_key
);
631 if (!NT_STATUS_IS_OK(status
)) {
632 r
->samr_handle
.out
.error_string
= talloc_asprintf(mem_ctx
,
633 "dcerpc_fetch_session_key failed: %s",
638 enc_session_key
= (gnutls_datum_t
) {
639 .data
= session_key
.data
,
640 .size
= session_key
.length
,
643 rc
= gnutls_cipher_init(&cipher_hnd
,
644 GNUTLS_CIPHER_ARCFOUR_128
,
648 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
652 rc
= gnutls_cipher_encrypt(cipher_hnd
,
653 u_info
.info24
.password
.data
,
655 gnutls_cipher_deinit(cipher_hnd
);
657 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
661 sui
.in
.user_handle
= r
->samr_handle
.in
.user_handle
;
662 sui
.in
.info
= &u_info
;
665 /* 9. try samr_SetUserInfo2 level 24 to set the password */
666 status
= dcerpc_samr_SetUserInfo2_r(r
->samr_handle
.in
.dcerpc_pipe
->binding_handle
, mem_ctx
, &sui
);
667 if (NT_STATUS_IS_OK(status
) && !NT_STATUS_IS_OK(sui
.out
.result
)) {
668 status
= sui
.out
.result
;
670 if (!NT_STATUS_IS_OK(status
)) {
671 r
->samr_handle
.out
.error_string
672 = talloc_asprintf(mem_ctx
,
673 "SetUserInfo2 level 24 for [%s] failed: %s",
674 r
->samr_handle
.in
.account_name
, nt_errstr(status
));
678 data_blob_clear(&session_key
);
682 static NTSTATUS
libnet_SetPassword_samr_handle_23(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, union libnet_SetPassword
*r
)
685 struct samr_SetUserInfo2 sui
;
686 union samr_UserInfo u_info
;
687 DATA_BLOB session_key
;
688 gnutls_cipher_hd_t cipher_hnd
= NULL
;
689 gnutls_datum_t _session_key
;
692 if (!r
->samr_handle
.in
.info21
) {
693 return NT_STATUS_INVALID_PARAMETER_MIX
;
696 /* prepare samr_SetUserInfo2 level 23 */
698 u_info
.info23
.info
= *r
->samr_handle
.in
.info21
;
699 u_info
.info23
.info
.fields_present
|= SAMR_FIELD_NT_PASSWORD_PRESENT
;
700 encode_pw_buffer(u_info
.info23
.password
.data
, r
->samr_handle
.in
.newpassword
, STR_UNICODE
);
702 status
= dcerpc_fetch_session_key(r
->samr_handle
.in
.dcerpc_pipe
, &session_key
);
703 if (!NT_STATUS_IS_OK(status
)) {
704 r
->samr_handle
.out
.error_string
705 = talloc_asprintf(mem_ctx
,
706 "dcerpc_fetch_session_key failed: %s",
711 _session_key
= (gnutls_datum_t
) {
712 .data
= session_key
.data
,
713 .size
= session_key
.length
,
716 rc
= gnutls_cipher_init(&cipher_hnd
,
717 GNUTLS_CIPHER_ARCFOUR_128
,
721 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
725 rc
= gnutls_cipher_encrypt(cipher_hnd
,
726 u_info
.info23
.password
.data
,
728 data_blob_clear_free(&session_key
);
729 gnutls_cipher_deinit(cipher_hnd
);
731 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
735 sui
.in
.user_handle
= r
->samr_handle
.in
.user_handle
;
736 sui
.in
.info
= &u_info
;
739 /* 10. try samr_SetUserInfo2 level 23 to set the password */
740 status
= dcerpc_samr_SetUserInfo2_r(r
->samr_handle
.in
.dcerpc_pipe
->binding_handle
, mem_ctx
, &sui
);
741 if (NT_STATUS_IS_OK(status
) && !NT_STATUS_IS_OK(sui
.out
.result
)) {
742 status
= sui
.out
.result
;
744 if (!NT_STATUS_IS_OK(status
)) {
745 r
->samr_handle
.out
.error_string
746 = talloc_asprintf(mem_ctx
,
747 "SetUserInfo2 level 23 for [%s] failed: %s",
748 r
->samr_handle
.in
.account_name
, nt_errstr(status
));
756 * 1. try samr_SetUserInfo2 level 26 to set the password
757 * 2. try samr_SetUserInfo2 level 25 to set the password
758 * 3. try samr_SetUserInfo2 level 24 to set the password
759 * 4. try samr_SetUserInfo2 level 23 to set the password
761 static NTSTATUS
libnet_SetPassword_samr_handle(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, union libnet_SetPassword
*r
)
765 enum libnet_SetPassword_level levels
[] = {
766 LIBNET_SET_PASSWORD_SAMR_HANDLE_26
,
767 LIBNET_SET_PASSWORD_SAMR_HANDLE_25
,
768 LIBNET_SET_PASSWORD_SAMR_HANDLE_24
,
769 LIBNET_SET_PASSWORD_SAMR_HANDLE_23
,
773 for (i
=0; i
< ARRAY_SIZE(levels
); i
++) {
774 r
->generic
.level
= levels
[i
];
775 status
= libnet_SetPassword(ctx
, mem_ctx
, r
);
776 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_INFO_CLASS
)
777 || NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER_MIX
)
778 || NT_STATUS_EQUAL(status
, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE
)) {
779 /* Try another password set mechanism */
788 * set a password with DCERPC/SAMR calls
789 * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
790 * is it correct to contact the the pdc of the domain of the user who's password should be set?
791 * 2. do a samr_Connect to get a policy handle
792 * 3. do a samr_LookupDomain to get the domain sid
793 * 4. do a samr_OpenDomain to get a domain handle
794 * 5. do a samr_LookupNames to get the users rid
795 * 6. do a samr_OpenUser to get a user handle
796 * 7 call libnet_SetPassword_samr_handle to set the password
798 static NTSTATUS
libnet_SetPassword_samr(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, union libnet_SetPassword
*r
)
801 struct libnet_RpcConnect c
;
802 struct samr_Connect sc
;
803 struct policy_handle p_handle
;
804 struct samr_LookupDomain ld
;
805 struct dom_sid2
*sid
= NULL
;
806 struct lsa_String d_name
;
807 struct samr_OpenDomain od
;
808 struct policy_handle d_handle
;
809 struct samr_LookupNames ln
;
810 struct samr_Ids rids
, types
;
811 struct samr_OpenUser ou
;
812 struct policy_handle u_handle
;
813 union libnet_SetPassword r2
;
816 /* prepare connect to the SAMR pipe of users domain PDC */
817 c
.level
= LIBNET_RPC_CONNECT_PDC
;
818 c
.in
.name
= r
->samr
.in
.domain_name
;
819 c
.in
.dcerpc_iface
= &ndr_table_samr
;
821 /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
822 status
= libnet_RpcConnect(ctx
, mem_ctx
, &c
);
823 if (!NT_STATUS_IS_OK(status
)) {
824 r
->samr
.out
.error_string
= talloc_asprintf(mem_ctx
,
825 "Connection to SAMR pipe of PDC of domain '%s' failed: %s",
826 r
->samr
.in
.domain_name
, nt_errstr(status
));
830 /* prepare samr_Connect */
831 ZERO_STRUCT(p_handle
);
832 sc
.in
.system_name
= NULL
;
833 sc
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
834 sc
.out
.connect_handle
= &p_handle
;
836 /* 2. do a samr_Connect to get a policy handle */
837 status
= dcerpc_samr_Connect_r(c
.out
.dcerpc_pipe
->binding_handle
, mem_ctx
, &sc
);
838 if (NT_STATUS_IS_OK(status
) && !NT_STATUS_IS_OK(sc
.out
.result
)) {
839 status
= sc
.out
.result
;
841 if (!NT_STATUS_IS_OK(status
)) {
842 r
->samr
.out
.error_string
= talloc_asprintf(mem_ctx
,
843 "samr_Connect failed: %s",
848 /* prepare samr_LookupDomain */
849 d_name
.string
= r
->samr
.in
.domain_name
;
850 ld
.in
.connect_handle
= &p_handle
;
851 ld
.in
.domain_name
= &d_name
;
854 /* 3. do a samr_LookupDomain to get the domain sid */
855 status
= dcerpc_samr_LookupDomain_r(c
.out
.dcerpc_pipe
->binding_handle
, mem_ctx
, &ld
);
856 if (NT_STATUS_IS_OK(status
) && !NT_STATUS_IS_OK(ld
.out
.result
)) {
857 status
= ld
.out
.result
;
859 if (!NT_STATUS_IS_OK(status
)) {
860 r
->samr
.out
.error_string
= talloc_asprintf(mem_ctx
,
861 "samr_LookupDomain for [%s] failed: %s",
862 r
->samr
.in
.domain_name
, nt_errstr(status
));
866 /* prepare samr_OpenDomain */
867 ZERO_STRUCT(d_handle
);
868 od
.in
.connect_handle
= &p_handle
;
869 od
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
870 od
.in
.sid
= *ld
.out
.sid
;
871 od
.out
.domain_handle
= &d_handle
;
873 /* 4. do a samr_OpenDomain to get a domain handle */
874 status
= dcerpc_samr_OpenDomain_r(c
.out
.dcerpc_pipe
->binding_handle
, mem_ctx
, &od
);
875 if (NT_STATUS_IS_OK(status
) && !NT_STATUS_IS_OK(od
.out
.result
)) {
876 status
= od
.out
.result
;
878 if (!NT_STATUS_IS_OK(status
)) {
879 r
->samr
.out
.error_string
= talloc_asprintf(mem_ctx
,
880 "samr_OpenDomain for [%s] failed: %s",
881 r
->samr
.in
.domain_name
, nt_errstr(status
));
885 /* prepare samr_LookupNames */
886 ln
.in
.domain_handle
= &d_handle
;
888 ln
.in
.names
= talloc_array(mem_ctx
, struct lsa_String
, 1);
890 ln
.out
.types
= &types
;
892 r
->samr
.out
.error_string
= "Out of Memory";
893 return NT_STATUS_NO_MEMORY
;
895 ln
.in
.names
[0].string
= r
->samr
.in
.account_name
;
897 /* 5. do a samr_LookupNames to get the users rid */
898 status
= dcerpc_samr_LookupNames_r(c
.out
.dcerpc_pipe
->binding_handle
, mem_ctx
, &ln
);
899 if (NT_STATUS_IS_OK(status
) && !NT_STATUS_IS_OK(ln
.out
.result
)) {
900 status
= ln
.out
.result
;
902 if (!NT_STATUS_IS_OK(status
)) {
903 r
->samr
.out
.error_string
= talloc_asprintf(mem_ctx
,
904 "samr_LookupNames for [%s] failed: %s",
905 r
->samr
.in
.account_name
, nt_errstr(status
));
909 /* check if we got one RID for the user */
910 if (ln
.out
.rids
->count
!= 1) {
911 r
->samr
.out
.error_string
= talloc_asprintf(mem_ctx
,
912 "samr_LookupNames for [%s] returns %d RIDs",
913 r
->samr
.in
.account_name
, ln
.out
.rids
->count
);
914 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
918 if (ln
.out
.types
->count
!= 1) {
919 r
->samr
.out
.error_string
= talloc_asprintf(mem_ctx
,
920 "samr_LookupNames for [%s] returns %d RID TYPEs",
921 r
->samr
.in
.account_name
, ln
.out
.types
->count
);
922 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
926 /* prepare samr_OpenUser */
927 ZERO_STRUCT(u_handle
);
928 ou
.in
.domain_handle
= &d_handle
;
929 ou
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
930 ou
.in
.rid
= ln
.out
.rids
->ids
[0];
931 ou
.out
.user_handle
= &u_handle
;
933 /* 6. do a samr_OpenUser to get a user handle */
934 status
= dcerpc_samr_OpenUser_r(c
.out
.dcerpc_pipe
->binding_handle
, mem_ctx
, &ou
);
935 if (NT_STATUS_IS_OK(status
) && !NT_STATUS_IS_OK(ou
.out
.result
)) {
936 status
= ou
.out
.result
;
938 if (!NT_STATUS_IS_OK(status
)) {
939 r
->samr
.out
.error_string
= talloc_asprintf(mem_ctx
,
940 "samr_OpenUser for [%s] failed: %s",
941 r
->samr
.in
.account_name
, nt_errstr(status
));
945 r2
.samr_handle
.level
= LIBNET_SET_PASSWORD_SAMR_HANDLE
;
946 r2
.samr_handle
.in
.account_name
= r
->samr
.in
.account_name
;
947 r2
.samr_handle
.in
.newpassword
= r
->samr
.in
.newpassword
;
948 r2
.samr_handle
.in
.user_handle
= &u_handle
;
949 r2
.samr_handle
.in
.dcerpc_pipe
= c
.out
.dcerpc_pipe
;
950 r2
.samr_handle
.in
.info21
= NULL
;
952 status
= libnet_SetPassword(ctx
, mem_ctx
, &r2
);
954 r
->generic
.out
.error_string
= r2
.samr_handle
.out
.error_string
;
957 /* close connection */
958 talloc_unlink(ctx
, c
.out
.dcerpc_pipe
);
963 static NTSTATUS
libnet_SetPassword_generic(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, union libnet_SetPassword
*r
)
966 union libnet_SetPassword r2
;
968 r2
.samr
.level
= LIBNET_SET_PASSWORD_SAMR
;
969 r2
.samr
.in
.account_name
= r
->generic
.in
.account_name
;
970 r2
.samr
.in
.domain_name
= r
->generic
.in
.domain_name
;
971 r2
.samr
.in
.newpassword
= r
->generic
.in
.newpassword
;
973 r
->generic
.out
.error_string
= "Unknown Error";
974 status
= libnet_SetPassword(ctx
, mem_ctx
, &r2
);
976 r
->generic
.out
.error_string
= r2
.samr
.out
.error_string
;
981 NTSTATUS
libnet_SetPassword(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, union libnet_SetPassword
*r
)
983 enum smb_encryption_setting encryption_state
=
984 cli_credentials_get_smb_encryption(ctx
->cred
);
985 NTSTATUS status
= NT_STATUS_INVALID_LEVEL
;
987 switch (r
->generic
.level
) {
988 case LIBNET_SET_PASSWORD_GENERIC
:
989 status
= libnet_SetPassword_generic(ctx
, mem_ctx
, r
);
991 case LIBNET_SET_PASSWORD_SAMR
:
992 status
= libnet_SetPassword_samr(ctx
, mem_ctx
, r
);
994 case LIBNET_SET_PASSWORD_SAMR_HANDLE
:
995 status
= libnet_SetPassword_samr_handle(ctx
, mem_ctx
, r
);
997 case LIBNET_SET_PASSWORD_SAMR_HANDLE_26
:
998 if (encryption_state
== SMB_ENCRYPTION_REQUIRED
) {
999 GNUTLS_FIPS140_SET_LAX_MODE();
1001 status
= libnet_SetPassword_samr_handle_26(ctx
, mem_ctx
, r
);
1003 case LIBNET_SET_PASSWORD_SAMR_HANDLE_25
:
1004 if (encryption_state
== SMB_ENCRYPTION_REQUIRED
) {
1005 GNUTLS_FIPS140_SET_LAX_MODE();
1007 status
= libnet_SetPassword_samr_handle_25(ctx
, mem_ctx
, r
);
1009 case LIBNET_SET_PASSWORD_SAMR_HANDLE_24
:
1010 if (encryption_state
== SMB_ENCRYPTION_REQUIRED
) {
1011 GNUTLS_FIPS140_SET_LAX_MODE();
1013 status
= libnet_SetPassword_samr_handle_24(ctx
, mem_ctx
, r
);
1015 case LIBNET_SET_PASSWORD_SAMR_HANDLE_23
:
1016 if (encryption_state
== SMB_ENCRYPTION_REQUIRED
) {
1017 GNUTLS_FIPS140_SET_LAX_MODE();
1019 status
= libnet_SetPassword_samr_handle_23(ctx
, mem_ctx
, r
);
1021 case LIBNET_SET_PASSWORD_KRB5
:
1022 status
= NT_STATUS_NOT_IMPLEMENTED
;
1024 case LIBNET_SET_PASSWORD_LDAP
:
1025 status
= NT_STATUS_NOT_IMPLEMENTED
;
1027 case LIBNET_SET_PASSWORD_RAP
:
1028 status
= NT_STATUS_NOT_IMPLEMENTED
;
1032 GNUTLS_FIPS140_SET_STRICT_MODE();