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
));
141 return NT_STATUS_INVALID_PARAMETER
;
144 /* Ensure we don't reuse any of this state. */
147 /* Store the machine account password we're going to use. */
148 memcpy(dc
->mach_pw
, machine_pwd
, 16);
150 fstrcpy(dc
->remote_machine
, "\\\\");
151 fstrcat(dc
->remote_machine
, server_name
);
153 fstrcpy(dc
->domain
, domain
);
155 fstr_sprintf( dc
->mach_acct
, "%s$", machine_account
);
158 /* Create the client challenge. */
159 generate_random_buffer(clnt_chal_send
.data
, 8);
161 /* Get the server challenge. */
162 result
= rpccli_netr_ServerReqChallenge(cli
, talloc_tos(),
167 if (!NT_STATUS_IS_OK(result
)) {
171 /* Calculate the session key and client credentials */
172 creds_client_init(*neg_flags_inout
,
180 * Send client auth-2 challenge and receive server repy.
183 result
= rpccli_netr_ServerAuthenticate2(cli
, talloc_tos(),
188 &clnt_chal_send
, /* input. */
189 &srv_chal_recv
, /* output. */
192 /* we might be talking to NT4, so let's downgrade in that case and retry
193 * with the returned neg_flags - gd */
195 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
) && !retried
) {
200 if (!NT_STATUS_IS_OK(result
)) {
205 * Check the returned value using the initial
206 * server received challenge.
209 if (!netlogon_creds_client_check(dc
, &srv_chal_recv
)) {
211 * Server replied with bad credential. Fail.
213 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
214 "replied with bad credential\n",
216 return NT_STATUS_ACCESS_DENIED
;
219 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
220 "chain established.\n",
226 /* Logon domain user */
228 NTSTATUS
rpccli_netlogon_sam_logon(struct rpc_pipe_client
*cli
,
230 uint32 logon_parameters
,
232 const char *username
,
233 const char *password
,
234 const char *workstation
,
237 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
238 struct netr_Authenticator clnt_creds
;
239 struct netr_Authenticator ret_creds
;
240 union netr_LogonInfo
*logon
;
241 union netr_Validation validation
;
242 uint8_t authoritative
;
243 int validation_level
= 3;
244 fstring clnt_name_slash
;
247 ZERO_STRUCT(ret_creds
);
250 logon
= TALLOC_ZERO_P(mem_ctx
, union netr_LogonInfo
);
252 return NT_STATUS_NO_MEMORY
;
256 fstr_sprintf( clnt_name_slash
, "\\\\%s", workstation
);
258 fstr_sprintf( clnt_name_slash
, "\\\\%s", global_myname() );
261 /* Initialise input parameters */
263 netlogon_creds_client_step(cli
->dc
, &clnt_creds
);
265 switch (logon_type
) {
266 case INTERACTIVE_LOGON_TYPE
: {
268 struct netr_PasswordInfo
*password_info
;
270 struct samr_Password lmpassword
;
271 struct samr_Password ntpassword
;
273 unsigned char lm_owf_user_pwd
[16], nt_owf_user_pwd
[16];
275 unsigned char lm_owf
[16];
276 unsigned char nt_owf
[16];
277 unsigned char key
[16];
279 password_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_PasswordInfo
);
280 if (!password_info
) {
281 return NT_STATUS_NO_MEMORY
;
284 nt_lm_owf_gen(password
, nt_owf_user_pwd
, lm_owf_user_pwd
);
286 #ifdef DEBUG_PASSWORD
287 DEBUG(100,("lm cypher:"));
288 dump_data(100, lm_owf_user_pwd
, 16);
290 DEBUG(100,("nt cypher:"));
291 dump_data(100, nt_owf_user_pwd
, 16);
294 memcpy(key
, cli
->dc
->sess_key
, 8);
296 memcpy(lm_owf
, lm_owf_user_pwd
, 16);
297 SamOEMhash(lm_owf
, key
, 16);
298 memcpy(nt_owf
, nt_owf_user_pwd
, 16);
299 SamOEMhash(nt_owf
, key
, 16);
301 #ifdef DEBUG_PASSWORD
302 DEBUG(100,("encrypt of lm owf password:"));
303 dump_data(100, lm_owf
, 16);
305 DEBUG(100,("encrypt of nt owf password:"));
306 dump_data(100, nt_owf
, 16);
308 memcpy(lmpassword
.hash
, lm_owf
, 16);
309 memcpy(ntpassword
.hash
, nt_owf
, 16);
311 init_netr_PasswordInfo(password_info
,
321 logon
->password
= password_info
;
325 case NET_LOGON_TYPE
: {
326 struct netr_NetworkInfo
*network_info
;
328 unsigned char local_lm_response
[24];
329 unsigned char local_nt_response
[24];
330 struct netr_ChallengeResponse lm
;
331 struct netr_ChallengeResponse nt
;
336 network_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_NetworkInfo
);
338 return NT_STATUS_NO_MEMORY
;
341 generate_random_buffer(chal
, 8);
343 SMBencrypt(password
, chal
, local_lm_response
);
344 SMBNTencrypt(password
, chal
, local_nt_response
);
347 lm
.data
= local_lm_response
;
350 nt
.data
= local_nt_response
;
352 init_netr_NetworkInfo(network_info
,
363 logon
->network
= network_info
;
368 DEBUG(0, ("switch value %d not supported\n",
370 return NT_STATUS_INVALID_INFO_CLASS
;
373 result
= rpccli_netr_LogonSamLogon(cli
, mem_ctx
,
374 cli
->dc
->remote_machine
,
384 if (memcmp(zeros
, &ret_creds
.cred
.data
, sizeof(ret_creds
.cred
.data
)) != 0) {
385 /* Check returned credentials if present. */
386 if (!netlogon_creds_client_check(cli
->dc
, &ret_creds
.cred
)) {
387 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
388 return NT_STATUS_ACCESS_DENIED
;
397 * Logon domain user with an 'network' SAM logon
399 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
402 NTSTATUS
rpccli_netlogon_sam_network_logon(struct rpc_pipe_client
*cli
,
404 uint32 logon_parameters
,
406 const char *username
,
408 const char *workstation
,
410 DATA_BLOB lm_response
,
411 DATA_BLOB nt_response
,
412 struct netr_SamInfo3
**info3
)
414 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
415 int validation_level
= 3;
416 const char *workstation_name_slash
;
417 const char *server_name_slash
;
419 struct netr_Authenticator clnt_creds
;
420 struct netr_Authenticator ret_creds
;
421 union netr_LogonInfo
*logon
= NULL
;
422 struct netr_NetworkInfo
*network_info
;
423 uint8_t authoritative
;
424 union netr_Validation validation
;
425 struct netr_ChallengeResponse lm
;
426 struct netr_ChallengeResponse nt
;
427 struct netr_UserSessionKey user_session_key
;
428 struct netr_LMSessionKey lmsesskey
;
433 ZERO_STRUCT(ret_creds
);
438 logon
= TALLOC_ZERO_P(mem_ctx
, union netr_LogonInfo
);
440 return NT_STATUS_NO_MEMORY
;
443 network_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_NetworkInfo
);
445 return NT_STATUS_NO_MEMORY
;
448 netlogon_creds_client_step(cli
->dc
, &clnt_creds
);
450 if (server
[0] != '\\' && server
[1] != '\\') {
451 server_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", server
);
453 server_name_slash
= server
;
456 if (workstation
[0] != '\\' && workstation
[1] != '\\') {
457 workstation_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", workstation
);
459 workstation_name_slash
= workstation
;
462 if (!workstation_name_slash
|| !server_name_slash
) {
463 DEBUG(0, ("talloc_asprintf failed!\n"));
464 return NT_STATUS_NO_MEMORY
;
467 /* Initialise input parameters */
469 lm
.data
= lm_response
.data
;
470 lm
.length
= lm_response
.length
;
471 nt
.data
= nt_response
.data
;
472 nt
.length
= nt_response
.length
;
474 init_netr_NetworkInfo(network_info
,
480 workstation_name_slash
,
485 logon
->network
= network_info
;
487 /* Marshall data and send request */
489 result
= rpccli_netr_LogonSamLogon(cli
, mem_ctx
,
499 if (!NT_STATUS_IS_OK(result
)) {
503 user_session_key
= validation
.sam3
->base
.key
;
504 lmsesskey
= validation
.sam3
->base
.LMSessKey
;
506 if (memcmp(zeros
, user_session_key
.key
, 16) != 0) {
507 SamOEMhash(user_session_key
.key
, cli
->dc
->sess_key
, 16);
510 if (memcmp(zeros
, lmsesskey
.key
, 8) != 0) {
511 SamOEMhash(lmsesskey
.key
, cli
->dc
->sess_key
, 8);
514 if (memcmp(zeros
, ret_creds
.cred
.data
, sizeof(ret_creds
.cred
.data
)) != 0) {
515 /* Check returned credentials if present. */
516 if (!netlogon_creds_client_check(cli
->dc
, &ret_creds
.cred
)) {
517 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
518 return NT_STATUS_ACCESS_DENIED
;
522 *info3
= validation
.sam3
;
527 NTSTATUS
rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client
*cli
,
529 uint32 logon_parameters
,
531 const char *username
,
533 const char *workstation
,
535 DATA_BLOB lm_response
,
536 DATA_BLOB nt_response
,
537 struct netr_SamInfo3
**info3
)
539 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
540 int validation_level
= 3;
541 const char *workstation_name_slash
;
542 const char *server_name_slash
;
544 union netr_LogonInfo
*logon
= NULL
;
545 struct netr_NetworkInfo
*network_info
;
546 uint8_t authoritative
;
547 union netr_Validation validation
;
548 struct netr_ChallengeResponse lm
;
549 struct netr_ChallengeResponse nt
;
550 struct netr_UserSessionKey user_session_key
;
551 struct netr_LMSessionKey lmsesskey
;
561 logon
= TALLOC_ZERO_P(mem_ctx
, union netr_LogonInfo
);
563 return NT_STATUS_NO_MEMORY
;
566 network_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_NetworkInfo
);
568 return NT_STATUS_NO_MEMORY
;
571 if (server
[0] != '\\' && server
[1] != '\\') {
572 server_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", server
);
574 server_name_slash
= server
;
577 if (workstation
[0] != '\\' && workstation
[1] != '\\') {
578 workstation_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", workstation
);
580 workstation_name_slash
= workstation
;
583 if (!workstation_name_slash
|| !server_name_slash
) {
584 DEBUG(0, ("talloc_asprintf failed!\n"));
585 return NT_STATUS_NO_MEMORY
;
588 /* Initialise input parameters */
590 lm
.data
= lm_response
.data
;
591 lm
.length
= lm_response
.length
;
592 nt
.data
= nt_response
.data
;
593 nt
.length
= nt_response
.length
;
595 init_netr_NetworkInfo(network_info
,
601 workstation_name_slash
,
606 logon
->network
= network_info
;
608 /* Marshall data and send request */
610 result
= rpccli_netr_LogonSamLogonEx(cli
, mem_ctx
,
619 if (!NT_STATUS_IS_OK(result
)) {
623 user_session_key
= validation
.sam3
->base
.key
;
624 lmsesskey
= validation
.sam3
->base
.LMSessKey
;
626 if (memcmp(zeros
, user_session_key
.key
, 16) != 0) {
627 SamOEMhash(user_session_key
.key
, cli
->dc
->sess_key
, 16);
630 if (memcmp(zeros
, lmsesskey
.key
, 8) != 0) {
631 SamOEMhash(lmsesskey
.key
, cli
->dc
->sess_key
, 8);
634 *info3
= validation
.sam3
;