2 Unix SMB/CIFS implementation.
3 NT Domain Authentication SMB / MSRPC client
4 Copyright (C) Andrew Tridgell 1992-2000
5 Copyright (C) Jeremy Allison 1998.
6 Largely re-written by Jeremy Allison (C) 2005.
7 Copyright (C) Guenther Deschner 2008.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "../libcli/auth/libcli_auth.h"
26 /****************************************************************************
27 Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
28 credentials chain. Stores the credentials in the struct dcinfo in the
30 ****************************************************************************/
32 NTSTATUS
rpccli_netlogon_setup_creds(struct rpc_pipe_client
*cli
,
33 const char *server_name
,
35 const char *clnt_name
,
36 const char *machine_account
,
37 const unsigned char machine_pwd
[16],
38 enum netr_SchannelType sec_chan_type
,
39 uint32_t *neg_flags_inout
)
41 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
42 struct netr_Credential clnt_chal_send
;
43 struct netr_Credential srv_chal_recv
;
44 struct netr_Credentials
*dc
;
47 SMB_ASSERT(ndr_syntax_id_equal(&cli
->abstract_syntax
,
48 &ndr_table_netlogon
.syntax_id
));
51 cli
->dc
= talloc_zero(cli
, struct dcinfo
);
52 if (cli
->dc
== NULL
) {
53 return NT_STATUS_NO_MEMORY
;
57 /* Store the machine account password we're going to use. */
58 memcpy(dc
->mach_pw
, machine_pwd
, 16);
60 fstrcpy(dc
->remote_machine
, "\\\\");
61 fstrcat(dc
->remote_machine
, server_name
);
63 fstrcpy(dc
->domain
, domain
);
65 fstr_sprintf( dc
->mach_acct
, "%s$", machine_account
);
68 /* Create the client challenge. */
69 generate_random_buffer(clnt_chal_send
.data
, 8);
71 /* Get the server challenge. */
72 result
= rpccli_netr_ServerReqChallenge(cli
, talloc_tos(),
77 if (!NT_STATUS_IS_OK(result
)) {
81 /* Calculate the session key and client credentials */
82 creds_client_init(*neg_flags_inout
,
90 * Send client auth-2 challenge and receive server repy.
93 result
= rpccli_netr_ServerAuthenticate2(cli
, talloc_tos(),
98 &clnt_chal_send
, /* input. */
99 &srv_chal_recv
, /* output. */
102 /* we might be talking to NT4, so let's downgrade in that case and retry
103 * with the returned neg_flags - gd */
105 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
) && !retried
) {
110 if (!NT_STATUS_IS_OK(result
)) {
115 * Check the returned value using the initial
116 * server received challenge.
119 if (!netlogon_creds_client_check(dc
, &srv_chal_recv
)) {
121 * Server replied with bad credential. Fail.
123 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
124 "replied with bad credential\n",
126 return NT_STATUS_ACCESS_DENIED
;
129 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
130 "chain established.\n",
136 /* Logon domain user */
138 NTSTATUS
rpccli_netlogon_sam_logon(struct rpc_pipe_client
*cli
,
140 uint32 logon_parameters
,
142 const char *username
,
143 const char *password
,
144 const char *workstation
,
147 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
148 struct netr_Authenticator clnt_creds
;
149 struct netr_Authenticator ret_creds
;
150 union netr_LogonLevel
*logon
;
151 union netr_Validation validation
;
152 uint8_t authoritative
;
153 int validation_level
= 3;
154 fstring clnt_name_slash
;
157 ZERO_STRUCT(ret_creds
);
160 logon
= TALLOC_ZERO_P(mem_ctx
, union netr_LogonLevel
);
162 return NT_STATUS_NO_MEMORY
;
166 fstr_sprintf( clnt_name_slash
, "\\\\%s", workstation
);
168 fstr_sprintf( clnt_name_slash
, "\\\\%s", global_myname() );
171 /* Initialise input parameters */
173 netlogon_creds_client_step(cli
->dc
, &clnt_creds
);
175 switch (logon_type
) {
176 case NetlogonInteractiveInformation
: {
178 struct netr_PasswordInfo
*password_info
;
180 struct samr_Password lmpassword
;
181 struct samr_Password ntpassword
;
183 unsigned char lm_owf_user_pwd
[16], nt_owf_user_pwd
[16];
185 unsigned char lm_owf
[16];
186 unsigned char nt_owf
[16];
187 unsigned char key
[16];
189 password_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_PasswordInfo
);
190 if (!password_info
) {
191 return NT_STATUS_NO_MEMORY
;
194 nt_lm_owf_gen(password
, nt_owf_user_pwd
, lm_owf_user_pwd
);
196 #ifdef DEBUG_PASSWORD
197 DEBUG(100,("lm cypher:"));
198 dump_data(100, lm_owf_user_pwd
, 16);
200 DEBUG(100,("nt cypher:"));
201 dump_data(100, nt_owf_user_pwd
, 16);
204 memcpy(key
, cli
->dc
->sess_key
, 8);
206 memcpy(lm_owf
, lm_owf_user_pwd
, 16);
207 arcfour_crypt(lm_owf
, key
, 16);
208 memcpy(nt_owf
, nt_owf_user_pwd
, 16);
209 arcfour_crypt(nt_owf
, key
, 16);
211 #ifdef DEBUG_PASSWORD
212 DEBUG(100,("encrypt of lm owf password:"));
213 dump_data(100, lm_owf
, 16);
215 DEBUG(100,("encrypt of nt owf password:"));
216 dump_data(100, nt_owf
, 16);
218 memcpy(lmpassword
.hash
, lm_owf
, 16);
219 memcpy(ntpassword
.hash
, nt_owf
, 16);
221 init_netr_PasswordInfo(password_info
,
231 logon
->password
= password_info
;
235 case NetlogonNetworkInformation
: {
236 struct netr_NetworkInfo
*network_info
;
238 unsigned char local_lm_response
[24];
239 unsigned char local_nt_response
[24];
240 struct netr_ChallengeResponse lm
;
241 struct netr_ChallengeResponse nt
;
246 network_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_NetworkInfo
);
248 return NT_STATUS_NO_MEMORY
;
251 generate_random_buffer(chal
, 8);
253 SMBencrypt(password
, chal
, local_lm_response
);
254 SMBNTencrypt(password
, chal
, local_nt_response
);
257 lm
.data
= local_lm_response
;
260 nt
.data
= local_nt_response
;
262 init_netr_NetworkInfo(network_info
,
273 logon
->network
= network_info
;
278 DEBUG(0, ("switch value %d not supported\n",
280 return NT_STATUS_INVALID_INFO_CLASS
;
283 result
= rpccli_netr_LogonSamLogon(cli
, mem_ctx
,
284 cli
->dc
->remote_machine
,
294 if (memcmp(zeros
, &ret_creds
.cred
.data
, sizeof(ret_creds
.cred
.data
)) != 0) {
295 /* Check returned credentials if present. */
296 if (!netlogon_creds_client_check(cli
->dc
, &ret_creds
.cred
)) {
297 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
298 return NT_STATUS_ACCESS_DENIED
;
307 * Logon domain user with an 'network' SAM logon
309 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
312 NTSTATUS
rpccli_netlogon_sam_network_logon(struct rpc_pipe_client
*cli
,
314 uint32 logon_parameters
,
316 const char *username
,
318 const char *workstation
,
320 DATA_BLOB lm_response
,
321 DATA_BLOB nt_response
,
322 struct netr_SamInfo3
**info3
)
324 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
325 int validation_level
= 3;
326 const char *workstation_name_slash
;
327 const char *server_name_slash
;
329 struct netr_Authenticator clnt_creds
;
330 struct netr_Authenticator ret_creds
;
331 union netr_LogonLevel
*logon
= NULL
;
332 struct netr_NetworkInfo
*network_info
;
333 uint8_t authoritative
;
334 union netr_Validation validation
;
335 struct netr_ChallengeResponse lm
;
336 struct netr_ChallengeResponse nt
;
341 ZERO_STRUCT(ret_creds
);
346 logon
= TALLOC_ZERO_P(mem_ctx
, union netr_LogonLevel
);
348 return NT_STATUS_NO_MEMORY
;
351 network_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_NetworkInfo
);
353 return NT_STATUS_NO_MEMORY
;
356 netlogon_creds_client_step(cli
->dc
, &clnt_creds
);
358 if (server
[0] != '\\' && server
[1] != '\\') {
359 server_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", server
);
361 server_name_slash
= server
;
364 if (workstation
[0] != '\\' && workstation
[1] != '\\') {
365 workstation_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", workstation
);
367 workstation_name_slash
= workstation
;
370 if (!workstation_name_slash
|| !server_name_slash
) {
371 DEBUG(0, ("talloc_asprintf failed!\n"));
372 return NT_STATUS_NO_MEMORY
;
375 /* Initialise input parameters */
377 lm
.data
= lm_response
.data
;
378 lm
.length
= lm_response
.length
;
379 nt
.data
= nt_response
.data
;
380 nt
.length
= nt_response
.length
;
382 init_netr_NetworkInfo(network_info
,
388 workstation_name_slash
,
393 logon
->network
= network_info
;
395 /* Marshall data and send request */
397 result
= rpccli_netr_LogonSamLogon(cli
, mem_ctx
,
402 NetlogonNetworkInformation
,
407 if (!NT_STATUS_IS_OK(result
)) {
411 if (memcmp(zeros
, validation
.sam3
->base
.key
.key
, 16) != 0) {
412 arcfour_crypt(validation
.sam3
->base
.key
.key
,
413 cli
->dc
->sess_key
, 16);
416 if (memcmp(zeros
, validation
.sam3
->base
.LMSessKey
.key
, 8) != 0) {
417 arcfour_crypt(validation
.sam3
->base
.LMSessKey
.key
,
418 cli
->dc
->sess_key
, 8);
421 if (memcmp(zeros
, ret_creds
.cred
.data
, sizeof(ret_creds
.cred
.data
)) != 0) {
422 /* Check returned credentials if present. */
423 if (!netlogon_creds_client_check(cli
->dc
, &ret_creds
.cred
)) {
424 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
425 return NT_STATUS_ACCESS_DENIED
;
429 *info3
= validation
.sam3
;
434 NTSTATUS
rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client
*cli
,
436 uint32 logon_parameters
,
438 const char *username
,
440 const char *workstation
,
442 DATA_BLOB lm_response
,
443 DATA_BLOB nt_response
,
444 struct netr_SamInfo3
**info3
)
446 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
447 int validation_level
= 3;
448 const char *workstation_name_slash
;
449 const char *server_name_slash
;
451 union netr_LogonLevel
*logon
= NULL
;
452 struct netr_NetworkInfo
*network_info
;
453 uint8_t authoritative
;
454 union netr_Validation validation
;
455 struct netr_ChallengeResponse lm
;
456 struct netr_ChallengeResponse nt
;
466 logon
= TALLOC_ZERO_P(mem_ctx
, union netr_LogonLevel
);
468 return NT_STATUS_NO_MEMORY
;
471 network_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_NetworkInfo
);
473 return NT_STATUS_NO_MEMORY
;
476 if (server
[0] != '\\' && server
[1] != '\\') {
477 server_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", server
);
479 server_name_slash
= server
;
482 if (workstation
[0] != '\\' && workstation
[1] != '\\') {
483 workstation_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", workstation
);
485 workstation_name_slash
= workstation
;
488 if (!workstation_name_slash
|| !server_name_slash
) {
489 DEBUG(0, ("talloc_asprintf failed!\n"));
490 return NT_STATUS_NO_MEMORY
;
493 /* Initialise input parameters */
495 lm
.data
= lm_response
.data
;
496 lm
.length
= lm_response
.length
;
497 nt
.data
= nt_response
.data
;
498 nt
.length
= nt_response
.length
;
500 init_netr_NetworkInfo(network_info
,
506 workstation_name_slash
,
511 logon
->network
= network_info
;
513 /* Marshall data and send request */
515 result
= rpccli_netr_LogonSamLogonEx(cli
, mem_ctx
,
518 NetlogonNetworkInformation
,
524 if (!NT_STATUS_IS_OK(result
)) {
528 if (memcmp(zeros
, validation
.sam3
->base
.key
.key
, 16) != 0) {
529 arcfour_crypt(validation
.sam3
->base
.key
.key
,
530 cli
->dc
->sess_key
, 16);
533 if (memcmp(zeros
, validation
.sam3
->base
.LMSessKey
.key
, 8) != 0) {
534 arcfour_crypt(validation
.sam3
->base
.LMSessKey
.key
,
535 cli
->dc
->sess_key
, 8);
538 *info3
= validation
.sam3
;
543 /*********************************************************
544 Change the domain password on the PDC.
546 Just changes the password betwen the two values specified.
548 Caller must have the cli connected to the netlogon pipe
550 **********************************************************/
552 NTSTATUS
rpccli_netlogon_set_trust_password(struct rpc_pipe_client
*cli
,
554 const unsigned char orig_trust_passwd_hash
[16],
555 const char *new_trust_pwd_cleartext
,
556 const unsigned char new_trust_passwd_hash
[16],
557 uint32_t sec_channel_type
)
560 uint32_t neg_flags
= NETLOGON_NEG_AUTH2_ADS_FLAGS
;
561 struct netr_Authenticator clnt_creds
, srv_cred
;
563 result
= rpccli_netlogon_setup_creds(cli
,
564 cli
->desthost
, /* server name */
565 lp_workgroup(), /* domain */
566 global_myname(), /* client name */
567 global_myname(), /* machine account name */
568 orig_trust_passwd_hash
,
572 if (!NT_STATUS_IS_OK(result
)) {
573 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
578 netlogon_creds_client_step(cli
->dc
, &clnt_creds
);
580 if (neg_flags
& NETLOGON_NEG_PASSWORD_SET2
) {
582 struct netr_CryptPassword new_password
;
584 init_netr_CryptPassword(new_trust_pwd_cleartext
,
588 result
= rpccli_netr_ServerPasswordSet2(cli
, mem_ctx
,
589 cli
->dc
->remote_machine
,
596 if (!NT_STATUS_IS_OK(result
)) {
597 DEBUG(0,("rpccli_netr_ServerPasswordSet2 failed: %s\n",
603 struct samr_Password new_password
;
605 cred_hash3(new_password
.hash
,
606 new_trust_passwd_hash
,
607 cli
->dc
->sess_key
, 1);
609 result
= rpccli_netr_ServerPasswordSet(cli
, mem_ctx
,
610 cli
->dc
->remote_machine
,
617 if (!NT_STATUS_IS_OK(result
)) {
618 DEBUG(0,("rpccli_netr_ServerPasswordSet failed: %s\n",
624 /* Always check returned credentials. */
625 if (!netlogon_creds_client_check(cli
->dc
, &srv_cred
.cred
)) {
626 DEBUG(0,("credentials chain check failed\n"));
627 return NT_STATUS_ACCESS_DENIED
;