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 /****************************************************************************
26 Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
27 credentials chain. Stores the credentials in the struct dcinfo in the
29 ****************************************************************************/
31 NTSTATUS
rpccli_netlogon_setup_creds(struct rpc_pipe_client
*cli
,
32 const char *server_name
,
34 const char *clnt_name
,
35 const char *machine_account
,
36 const unsigned char machine_pwd
[16],
37 enum netr_SchannelType sec_chan_type
,
38 uint32_t *neg_flags_inout
)
40 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
41 struct netr_Credential clnt_chal_send
;
42 struct netr_Credential srv_chal_recv
;
46 SMB_ASSERT(ndr_syntax_id_equal(&cli
->abstract_syntax
,
47 &ndr_table_netlogon
.syntax_id
));
50 cli
->dc
= talloc_zero(cli
, struct dcinfo
);
51 if (cli
->dc
== NULL
) {
52 return NT_STATUS_NO_MEMORY
;
56 /* Store the machine account password we're going to use. */
57 memcpy(dc
->mach_pw
, machine_pwd
, 16);
59 fstrcpy(dc
->remote_machine
, "\\\\");
60 fstrcat(dc
->remote_machine
, server_name
);
62 fstrcpy(dc
->domain
, domain
);
64 fstr_sprintf( dc
->mach_acct
, "%s$", machine_account
);
67 /* Create the client challenge. */
68 generate_random_buffer(clnt_chal_send
.data
, 8);
70 /* Get the server challenge. */
71 result
= rpccli_netr_ServerReqChallenge(cli
, talloc_tos(),
76 if (!NT_STATUS_IS_OK(result
)) {
80 /* Calculate the session key and client credentials */
81 creds_client_init(*neg_flags_inout
,
89 * Send client auth-2 challenge and receive server repy.
92 result
= rpccli_netr_ServerAuthenticate2(cli
, talloc_tos(),
97 &clnt_chal_send
, /* input. */
98 &srv_chal_recv
, /* output. */
101 /* we might be talking to NT4, so let's downgrade in that case and retry
102 * with the returned neg_flags - gd */
104 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
) && !retried
) {
109 if (!NT_STATUS_IS_OK(result
)) {
114 * Check the returned value using the initial
115 * server received challenge.
118 if (!netlogon_creds_client_check(dc
, &srv_chal_recv
)) {
120 * Server replied with bad credential. Fail.
122 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
123 "replied with bad credential\n",
125 return NT_STATUS_ACCESS_DENIED
;
128 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
129 "chain established.\n",
135 /* Logon domain user */
137 NTSTATUS
rpccli_netlogon_sam_logon(struct rpc_pipe_client
*cli
,
139 uint32 logon_parameters
,
141 const char *username
,
142 const char *password
,
143 const char *workstation
,
146 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
147 struct netr_Authenticator clnt_creds
;
148 struct netr_Authenticator ret_creds
;
149 union netr_LogonInfo
*logon
;
150 union netr_Validation validation
;
151 uint8_t authoritative
;
152 int validation_level
= 3;
153 fstring clnt_name_slash
;
156 ZERO_STRUCT(ret_creds
);
159 logon
= TALLOC_ZERO_P(mem_ctx
, union netr_LogonInfo
);
161 return NT_STATUS_NO_MEMORY
;
165 fstr_sprintf( clnt_name_slash
, "\\\\%s", workstation
);
167 fstr_sprintf( clnt_name_slash
, "\\\\%s", global_myname() );
170 /* Initialise input parameters */
172 netlogon_creds_client_step(cli
->dc
, &clnt_creds
);
174 switch (logon_type
) {
175 case INTERACTIVE_LOGON_TYPE
: {
177 struct netr_PasswordInfo
*password_info
;
179 struct samr_Password lmpassword
;
180 struct samr_Password ntpassword
;
182 unsigned char lm_owf_user_pwd
[16], nt_owf_user_pwd
[16];
184 unsigned char lm_owf
[16];
185 unsigned char nt_owf
[16];
186 unsigned char key
[16];
188 password_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_PasswordInfo
);
189 if (!password_info
) {
190 return NT_STATUS_NO_MEMORY
;
193 nt_lm_owf_gen(password
, nt_owf_user_pwd
, lm_owf_user_pwd
);
195 #ifdef DEBUG_PASSWORD
196 DEBUG(100,("lm cypher:"));
197 dump_data(100, lm_owf_user_pwd
, 16);
199 DEBUG(100,("nt cypher:"));
200 dump_data(100, nt_owf_user_pwd
, 16);
203 memcpy(key
, cli
->dc
->sess_key
, 8);
205 memcpy(lm_owf
, lm_owf_user_pwd
, 16);
206 SamOEMhash(lm_owf
, key
, 16);
207 memcpy(nt_owf
, nt_owf_user_pwd
, 16);
208 SamOEMhash(nt_owf
, key
, 16);
210 #ifdef DEBUG_PASSWORD
211 DEBUG(100,("encrypt of lm owf password:"));
212 dump_data(100, lm_owf
, 16);
214 DEBUG(100,("encrypt of nt owf password:"));
215 dump_data(100, nt_owf
, 16);
217 memcpy(lmpassword
.hash
, lm_owf
, 16);
218 memcpy(ntpassword
.hash
, nt_owf
, 16);
220 init_netr_PasswordInfo(password_info
,
230 logon
->password
= password_info
;
234 case NET_LOGON_TYPE
: {
235 struct netr_NetworkInfo
*network_info
;
237 unsigned char local_lm_response
[24];
238 unsigned char local_nt_response
[24];
239 struct netr_ChallengeResponse lm
;
240 struct netr_ChallengeResponse nt
;
245 network_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_NetworkInfo
);
247 return NT_STATUS_NO_MEMORY
;
250 generate_random_buffer(chal
, 8);
252 SMBencrypt(password
, chal
, local_lm_response
);
253 SMBNTencrypt(password
, chal
, local_nt_response
);
256 lm
.data
= local_lm_response
;
259 nt
.data
= local_nt_response
;
261 init_netr_NetworkInfo(network_info
,
272 logon
->network
= network_info
;
277 DEBUG(0, ("switch value %d not supported\n",
279 return NT_STATUS_INVALID_INFO_CLASS
;
282 result
= rpccli_netr_LogonSamLogon(cli
, mem_ctx
,
283 cli
->dc
->remote_machine
,
293 if (memcmp(zeros
, &ret_creds
.cred
.data
, sizeof(ret_creds
.cred
.data
)) != 0) {
294 /* Check returned credentials if present. */
295 if (!netlogon_creds_client_check(cli
->dc
, &ret_creds
.cred
)) {
296 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
297 return NT_STATUS_ACCESS_DENIED
;
306 * Logon domain user with an 'network' SAM logon
308 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
311 NTSTATUS
rpccli_netlogon_sam_network_logon(struct rpc_pipe_client
*cli
,
313 uint32 logon_parameters
,
315 const char *username
,
317 const char *workstation
,
319 DATA_BLOB lm_response
,
320 DATA_BLOB nt_response
,
321 struct netr_SamInfo3
**info3
)
323 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
324 int validation_level
= 3;
325 const char *workstation_name_slash
;
326 const char *server_name_slash
;
328 struct netr_Authenticator clnt_creds
;
329 struct netr_Authenticator ret_creds
;
330 union netr_LogonInfo
*logon
= NULL
;
331 struct netr_NetworkInfo
*network_info
;
332 uint8_t authoritative
;
333 union netr_Validation validation
;
334 struct netr_ChallengeResponse lm
;
335 struct netr_ChallengeResponse nt
;
340 ZERO_STRUCT(ret_creds
);
345 logon
= TALLOC_ZERO_P(mem_ctx
, union netr_LogonInfo
);
347 return NT_STATUS_NO_MEMORY
;
350 network_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_NetworkInfo
);
352 return NT_STATUS_NO_MEMORY
;
355 netlogon_creds_client_step(cli
->dc
, &clnt_creds
);
357 if (server
[0] != '\\' && server
[1] != '\\') {
358 server_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", server
);
360 server_name_slash
= server
;
363 if (workstation
[0] != '\\' && workstation
[1] != '\\') {
364 workstation_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", workstation
);
366 workstation_name_slash
= workstation
;
369 if (!workstation_name_slash
|| !server_name_slash
) {
370 DEBUG(0, ("talloc_asprintf failed!\n"));
371 return NT_STATUS_NO_MEMORY
;
374 /* Initialise input parameters */
376 lm
.data
= lm_response
.data
;
377 lm
.length
= lm_response
.length
;
378 nt
.data
= nt_response
.data
;
379 nt
.length
= nt_response
.length
;
381 init_netr_NetworkInfo(network_info
,
387 workstation_name_slash
,
392 logon
->network
= network_info
;
394 /* Marshall data and send request */
396 result
= rpccli_netr_LogonSamLogon(cli
, mem_ctx
,
406 if (!NT_STATUS_IS_OK(result
)) {
410 if (memcmp(zeros
, validation
.sam3
->base
.key
.key
, 16) != 0) {
411 SamOEMhash(validation
.sam3
->base
.key
.key
,
412 cli
->dc
->sess_key
, 16);
415 if (memcmp(zeros
, validation
.sam3
->base
.LMSessKey
.key
, 8) != 0) {
416 SamOEMhash(validation
.sam3
->base
.LMSessKey
.key
,
417 cli
->dc
->sess_key
, 8);
420 if (memcmp(zeros
, ret_creds
.cred
.data
, sizeof(ret_creds
.cred
.data
)) != 0) {
421 /* Check returned credentials if present. */
422 if (!netlogon_creds_client_check(cli
->dc
, &ret_creds
.cred
)) {
423 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
424 return NT_STATUS_ACCESS_DENIED
;
428 *info3
= validation
.sam3
;
433 NTSTATUS
rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client
*cli
,
435 uint32 logon_parameters
,
437 const char *username
,
439 const char *workstation
,
441 DATA_BLOB lm_response
,
442 DATA_BLOB nt_response
,
443 struct netr_SamInfo3
**info3
)
445 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
446 int validation_level
= 3;
447 const char *workstation_name_slash
;
448 const char *server_name_slash
;
450 union netr_LogonInfo
*logon
= NULL
;
451 struct netr_NetworkInfo
*network_info
;
452 uint8_t authoritative
;
453 union netr_Validation validation
;
454 struct netr_ChallengeResponse lm
;
455 struct netr_ChallengeResponse nt
;
456 struct netr_UserSessionKey user_session_key
;
457 struct netr_LMSessionKey lmsesskey
;
467 logon
= TALLOC_ZERO_P(mem_ctx
, union netr_LogonInfo
);
469 return NT_STATUS_NO_MEMORY
;
472 network_info
= TALLOC_ZERO_P(mem_ctx
, struct netr_NetworkInfo
);
474 return NT_STATUS_NO_MEMORY
;
477 if (server
[0] != '\\' && server
[1] != '\\') {
478 server_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", server
);
480 server_name_slash
= server
;
483 if (workstation
[0] != '\\' && workstation
[1] != '\\') {
484 workstation_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", workstation
);
486 workstation_name_slash
= workstation
;
489 if (!workstation_name_slash
|| !server_name_slash
) {
490 DEBUG(0, ("talloc_asprintf failed!\n"));
491 return NT_STATUS_NO_MEMORY
;
494 /* Initialise input parameters */
496 lm
.data
= lm_response
.data
;
497 lm
.length
= lm_response
.length
;
498 nt
.data
= nt_response
.data
;
499 nt
.length
= nt_response
.length
;
501 init_netr_NetworkInfo(network_info
,
507 workstation_name_slash
,
512 logon
->network
= network_info
;
514 /* Marshall data and send request */
516 result
= rpccli_netr_LogonSamLogonEx(cli
, mem_ctx
,
525 if (!NT_STATUS_IS_OK(result
)) {
529 user_session_key
= validation
.sam3
->base
.key
;
530 lmsesskey
= validation
.sam3
->base
.LMSessKey
;
532 if (memcmp(zeros
, user_session_key
.key
, 16) != 0) {
533 SamOEMhash(user_session_key
.key
, cli
->dc
->sess_key
, 16);
536 if (memcmp(zeros
, lmsesskey
.key
, 8) != 0) {
537 SamOEMhash(lmsesskey
.key
, cli
->dc
->sess_key
, 8);
540 *info3
= validation
.sam3
;