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/>.
25 /* LSA Request Challenge. Sends our challenge to server, then gets
26 server response. These are used to generate the credentials.
27 The sent and received challenges are stored in the netlog pipe
28 private data. Only call this via rpccli_netlogon_setup_creds(). JRA.
31 /* instead of rpccli_net_req_chal() we use rpccli_netr_ServerReqChallenge() now - gd */
34 /****************************************************************************
37 Send the client credential, receive back a server credential.
38 Ensure that the server credential returned matches the session key
39 encrypt of the server challenge originally received. JRA.
40 ****************************************************************************/
42 NTSTATUS
rpccli_net_auth2(struct rpc_pipe_client
*cli
,
44 uint32
*neg_flags
, DOM_CHAL
*srv_chal
)
46 prs_struct qbuf
, rbuf
;
49 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
52 if ( sec_chan
== SEC_CHAN_DOMAIN
)
53 fstr_sprintf( machine_acct
, "%s$", lp_workgroup() );
55 fstrcpy( machine_acct
, cli
->mach_acct
);
57 /* create and send a MSRPC command with api NET_AUTH2 */
59 DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
60 cli
->srv_name_slash
, machine_acct
, sec_chan
, global_myname(),
61 credstr(cli
->clnt_cred
.challenge
.data
), *neg_flags
));
63 /* store the parameters */
65 init_q_auth_2(&q
, cli
->srv_name_slash
, machine_acct
,
66 sec_chan
, global_myname(), &cli
->clnt_cred
.challenge
,
69 /* turn parameters into data stream */
71 CLI_DO_RPC(cli
, mem_ctx
, PI_NETLOGON
, NET_AUTH2
,
76 NT_STATUS_UNSUCCESSFUL
);
80 if (NT_STATUS_IS_OK(result
)) {
84 * Check the returned value using the initial
85 * server received challenge.
89 if (cred_assert( &r
.srv_chal
, cli
->sess_key
, srv_chal
, zerotime
) == 0) {
92 * Server replied with bad credential. Fail.
94 DEBUG(0,("cli_net_auth2: server %s replied with bad credential (bad machine \
95 password ?).\n", cli
->cli
->desthost
));
96 return NT_STATUS_ACCESS_DENIED
;
98 *neg_flags
= r
.srv_flgs
.neg_flags
;
105 /****************************************************************************
108 Send the client credential, receive back a server credential.
109 The caller *must* ensure that the server credential returned matches the session key
110 encrypt of the server challenge originally received. JRA.
111 ****************************************************************************/
113 /* instead of rpccli_net_auth2() we use rpccli_netr_ServerAuthenticate2() now - gd */
116 /****************************************************************************
117 Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
118 credentials chain. Stores the credentials in the struct dcinfo in the
119 netlogon pipe struct.
120 ****************************************************************************/
122 NTSTATUS
rpccli_netlogon_setup_creds(struct rpc_pipe_client
*cli
,
123 const char *server_name
,
125 const char *clnt_name
,
126 const char *machine_account
,
127 const unsigned char machine_pwd
[16],
128 enum netr_SchannelType sec_chan_type
,
129 uint32_t *neg_flags_inout
)
131 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
132 struct netr_Credential clnt_chal_send
;
133 struct netr_Credential srv_chal_recv
;
135 bool retried
= false;
137 SMB_ASSERT(rpccli_is_pipe_idx(cli
, PI_NETLOGON
));
139 TALLOC_FREE(cli
->dc
);
140 cli
->dc
= talloc_zero(cli
, struct dcinfo
);
141 if (cli
->dc
== NULL
) {
142 return NT_STATUS_NO_MEMORY
;
146 /* Store the machine account password we're going to use. */
147 memcpy(dc
->mach_pw
, machine_pwd
, 16);
149 fstrcpy(dc
->remote_machine
, "\\\\");
150 fstrcat(dc
->remote_machine
, server_name
);
152 fstrcpy(dc
->domain
, domain
);
154 fstr_sprintf( dc
->mach_acct
, "%s$", machine_account
);
157 /* Create the client challenge. */
158 generate_random_buffer(clnt_chal_send
.data
, 8);
160 /* Get the server challenge. */
161 result
= rpccli_netr_ServerReqChallenge(cli
, talloc_tos(),
166 if (!NT_STATUS_IS_OK(result
)) {
170 /* Calculate the session key and client credentials */
171 creds_client_init(*neg_flags_inout
,
179 * Send client auth-2 challenge and receive server repy.
182 result
= rpccli_netr_ServerAuthenticate2(cli
, talloc_tos(),
187 &clnt_chal_send
, /* input. */
188 &srv_chal_recv
, /* output. */
191 /* we might be talking to NT4, so let's downgrade in that case and retry
192 * with the returned neg_flags - gd */
194 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
) && !retried
) {
199 if (!NT_STATUS_IS_OK(result
)) {
204 * Check the returned value using the initial
205 * server received challenge.
208 if (!netlogon_creds_client_check(dc
, &srv_chal_recv
)) {
210 * Server replied with bad credential. Fail.
212 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
213 "replied with bad credential\n",
215 return NT_STATUS_ACCESS_DENIED
;
218 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
219 "chain established.\n",
225 /* Logon domain user */
227 NTSTATUS
rpccli_netlogon_sam_logon(struct rpc_pipe_client
*cli
,
229 uint32 logon_parameters
,
231 const char *username
,
232 const char *password
,
233 const char *workstation
,
236 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
237 struct netr_Authenticator clnt_creds
;
238 struct netr_Authenticator ret_creds
;
239 union netr_LogonInfo
*logon
;
240 union netr_Validation validation
;
241 uint8_t authoritative
;
242 int validation_level
= 3;
243 fstring clnt_name_slash
;
246 ZERO_STRUCT(ret_creds
);
249 logon
= TALLOC_ZERO_P(mem_ctx
, union netr_LogonInfo
);
251 return NT_STATUS_NO_MEMORY
;
255 fstr_sprintf( clnt_name_slash
, "\\\\%s", workstation
);
257 fstr_sprintf( clnt_name_slash
, "\\\\%s", global_myname() );
260 /* Initialise input parameters */
262 netlogon_creds_client_step(cli
->dc
, &clnt_creds
);
264 switch (logon_type
) {
265 case INTERACTIVE_LOGON_TYPE
: {
267 struct netr_PasswordInfo
*password_info
;
269 struct samr_Password lmpassword
;
270 struct samr_Password ntpassword
;
272 unsigned char lm_owf_user_pwd
[16], nt_owf_user_pwd
[16];
274 unsigned char lm_owf
[16];
275 unsigned char nt_owf
[16];
276 unsigned char key
[16];
278 password_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_PasswordInfo
);
279 if (!password_info
) {
280 return NT_STATUS_NO_MEMORY
;
283 nt_lm_owf_gen(password
, nt_owf_user_pwd
, lm_owf_user_pwd
);
285 #ifdef DEBUG_PASSWORD
286 DEBUG(100,("lm cypher:"));
287 dump_data(100, lm_owf_user_pwd
, 16);
289 DEBUG(100,("nt cypher:"));
290 dump_data(100, nt_owf_user_pwd
, 16);
293 memcpy(key
, cli
->dc
->sess_key
, 8);
295 memcpy(lm_owf
, lm_owf_user_pwd
, 16);
296 SamOEMhash(lm_owf
, key
, 16);
297 memcpy(nt_owf
, nt_owf_user_pwd
, 16);
298 SamOEMhash(nt_owf
, key
, 16);
300 #ifdef DEBUG_PASSWORD
301 DEBUG(100,("encrypt of lm owf password:"));
302 dump_data(100, lm_owf
, 16);
304 DEBUG(100,("encrypt of nt owf password:"));
305 dump_data(100, nt_owf
, 16);
307 memcpy(lmpassword
.hash
, lm_owf
, 16);
308 memcpy(ntpassword
.hash
, nt_owf
, 16);
310 init_netr_PasswordInfo(password_info
,
320 logon
->password
= password_info
;
324 case NET_LOGON_TYPE
: {
325 struct netr_NetworkInfo
*network_info
;
327 unsigned char local_lm_response
[24];
328 unsigned char local_nt_response
[24];
329 struct netr_ChallengeResponse lm
;
330 struct netr_ChallengeResponse nt
;
335 network_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_NetworkInfo
);
337 return NT_STATUS_NO_MEMORY
;
340 generate_random_buffer(chal
, 8);
342 SMBencrypt(password
, chal
, local_lm_response
);
343 SMBNTencrypt(password
, chal
, local_nt_response
);
346 lm
.data
= local_lm_response
;
349 nt
.data
= local_nt_response
;
351 init_netr_NetworkInfo(network_info
,
362 logon
->network
= network_info
;
367 DEBUG(0, ("switch value %d not supported\n",
369 return NT_STATUS_INVALID_INFO_CLASS
;
372 result
= rpccli_netr_LogonSamLogon(cli
, mem_ctx
,
373 cli
->dc
->remote_machine
,
383 if (memcmp(zeros
, &ret_creds
.cred
.data
, sizeof(ret_creds
.cred
.data
)) != 0) {
384 /* Check returned credentials if present. */
385 if (!netlogon_creds_client_check(cli
->dc
, &ret_creds
.cred
)) {
386 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
387 return NT_STATUS_ACCESS_DENIED
;
396 * Logon domain user with an 'network' SAM logon
398 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
401 NTSTATUS
rpccli_netlogon_sam_network_logon(struct rpc_pipe_client
*cli
,
403 uint32 logon_parameters
,
405 const char *username
,
407 const char *workstation
,
409 DATA_BLOB lm_response
,
410 DATA_BLOB nt_response
,
411 struct netr_SamInfo3
**info3
)
413 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
414 int validation_level
= 3;
415 const char *workstation_name_slash
;
416 const char *server_name_slash
;
418 struct netr_Authenticator clnt_creds
;
419 struct netr_Authenticator ret_creds
;
420 union netr_LogonInfo
*logon
= NULL
;
421 struct netr_NetworkInfo
*network_info
;
422 uint8_t authoritative
;
423 union netr_Validation validation
;
424 struct netr_ChallengeResponse lm
;
425 struct netr_ChallengeResponse nt
;
426 struct netr_UserSessionKey user_session_key
;
427 struct netr_LMSessionKey lmsesskey
;
432 ZERO_STRUCT(ret_creds
);
437 logon
= TALLOC_ZERO_P(mem_ctx
, union netr_LogonInfo
);
439 return NT_STATUS_NO_MEMORY
;
442 network_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_NetworkInfo
);
444 return NT_STATUS_NO_MEMORY
;
447 netlogon_creds_client_step(cli
->dc
, &clnt_creds
);
449 if (server
[0] != '\\' && server
[1] != '\\') {
450 server_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", server
);
452 server_name_slash
= server
;
455 if (workstation
[0] != '\\' && workstation
[1] != '\\') {
456 workstation_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", workstation
);
458 workstation_name_slash
= workstation
;
461 if (!workstation_name_slash
|| !server_name_slash
) {
462 DEBUG(0, ("talloc_asprintf failed!\n"));
463 return NT_STATUS_NO_MEMORY
;
466 /* Initialise input parameters */
468 lm
.data
= lm_response
.data
;
469 lm
.length
= lm_response
.length
;
470 nt
.data
= nt_response
.data
;
471 nt
.length
= nt_response
.length
;
473 init_netr_NetworkInfo(network_info
,
479 workstation_name_slash
,
484 logon
->network
= network_info
;
486 /* Marshall data and send request */
488 result
= rpccli_netr_LogonSamLogon(cli
, mem_ctx
,
498 if (!NT_STATUS_IS_OK(result
)) {
502 user_session_key
= validation
.sam3
->base
.key
;
503 lmsesskey
= validation
.sam3
->base
.LMSessKey
;
505 if (memcmp(zeros
, user_session_key
.key
, 16) != 0) {
506 SamOEMhash(user_session_key
.key
, cli
->dc
->sess_key
, 16);
509 if (memcmp(zeros
, lmsesskey
.key
, 8) != 0) {
510 SamOEMhash(lmsesskey
.key
, cli
->dc
->sess_key
, 8);
513 if (memcmp(zeros
, ret_creds
.cred
.data
, sizeof(ret_creds
.cred
.data
)) != 0) {
514 /* Check returned credentials if present. */
515 if (!netlogon_creds_client_check(cli
->dc
, &ret_creds
.cred
)) {
516 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
517 return NT_STATUS_ACCESS_DENIED
;
521 *info3
= validation
.sam3
;
526 NTSTATUS
rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client
*cli
,
528 uint32 logon_parameters
,
530 const char *username
,
532 const char *workstation
,
534 DATA_BLOB lm_response
,
535 DATA_BLOB nt_response
,
536 struct netr_SamInfo3
**info3
)
538 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
539 int validation_level
= 3;
540 const char *workstation_name_slash
;
541 const char *server_name_slash
;
543 union netr_LogonInfo
*logon
= NULL
;
544 struct netr_NetworkInfo
*network_info
;
545 uint8_t authoritative
;
546 union netr_Validation validation
;
547 struct netr_ChallengeResponse lm
;
548 struct netr_ChallengeResponse nt
;
549 struct netr_UserSessionKey user_session_key
;
550 struct netr_LMSessionKey lmsesskey
;
560 logon
= TALLOC_ZERO_P(mem_ctx
, union netr_LogonInfo
);
562 return NT_STATUS_NO_MEMORY
;
565 network_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_NetworkInfo
);
567 return NT_STATUS_NO_MEMORY
;
570 if (server
[0] != '\\' && server
[1] != '\\') {
571 server_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", server
);
573 server_name_slash
= server
;
576 if (workstation
[0] != '\\' && workstation
[1] != '\\') {
577 workstation_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", workstation
);
579 workstation_name_slash
= workstation
;
582 if (!workstation_name_slash
|| !server_name_slash
) {
583 DEBUG(0, ("talloc_asprintf failed!\n"));
584 return NT_STATUS_NO_MEMORY
;
587 /* Initialise input parameters */
589 lm
.data
= lm_response
.data
;
590 lm
.length
= lm_response
.length
;
591 nt
.data
= nt_response
.data
;
592 nt
.length
= nt_response
.length
;
594 init_netr_NetworkInfo(network_info
,
600 workstation_name_slash
,
605 logon
->network
= network_info
;
607 /* Marshall data and send request */
609 result
= rpccli_netr_LogonSamLogonEx(cli
, mem_ctx
,
618 if (!NT_STATUS_IS_OK(result
)) {
622 user_session_key
= validation
.sam3
->base
.key
;
623 lmsesskey
= validation
.sam3
->base
.LMSessKey
;
625 if (memcmp(zeros
, user_session_key
.key
, 16) != 0) {
626 SamOEMhash(user_session_key
.key
, cli
->dc
->sess_key
, 16);
629 if (memcmp(zeros
, lmsesskey
.key
, 8) != 0) {
630 SamOEMhash(lmsesskey
.key
, cli
->dc
->sess_key
, 8);
633 *info3
= validation
.sam3
;