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;
136 SMB_ASSERT(cli->pipe_idx == PI_NETLOGON);
140 return NT_STATUS_INVALID_PARAMETER;
143 /* Ensure we don't reuse any of this state. */
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);
156 /* Create the client challenge. */
157 generate_random_buffer(clnt_chal_send.data, 8);
159 /* Get the server challenge. */
160 result = rpccli_netr_ServerReqChallenge(cli, cli->mem_ctx,
165 if (!NT_STATUS_IS_OK(result)) {
169 /* Calculate the session key and client credentials */
170 creds_client_init(*neg_flags_inout,
178 * Send client auth-2 challenge and receive server repy.
181 result = rpccli_netr_ServerAuthenticate2(cli, cli->mem_ctx,
186 &clnt_chal_send, /* input. */
187 &srv_chal_recv, /* output. */
189 if (!NT_STATUS_IS_OK(result)) {
194 * Check the returned value using the initial
195 * server received challenge.
198 if (!netlogon_creds_client_check(dc, &srv_chal_recv)) {
200 * Server replied with bad credential. Fail.
202 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
203 "replied with bad credential\n",
204 cli->cli->desthost ));
205 return NT_STATUS_ACCESS_DENIED;
208 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
209 "chain established.\n",
210 cli->cli->desthost ));
215 /* Logon domain user */
217 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
219 uint32 logon_parameters,
221 const char *username,
222 const char *password,
223 const char *workstation,
226 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
227 struct netr_Authenticator clnt_creds;
228 struct netr_Authenticator ret_creds;
229 union netr_LogonLevel *logon;
230 union netr_Validation validation;
231 uint8_t authoritative;
232 int validation_level = 3;
233 fstring clnt_name_slash;
236 ZERO_STRUCT(ret_creds);
239 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
241 return NT_STATUS_NO_MEMORY;
245 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
247 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
250 /* Initialise input parameters */
252 netlogon_creds_client_step(cli->dc, &clnt_creds);
254 switch (logon_type) {
255 case INTERACTIVE_LOGON_TYPE: {
257 struct netr_PasswordInfo *password_info;
259 struct samr_Password lmpassword;
260 struct samr_Password ntpassword;
262 unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16];
264 unsigned char lm_owf[16];
265 unsigned char nt_owf[16];
266 unsigned char key[16];
268 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
269 if (!password_info) {
270 return NT_STATUS_NO_MEMORY;
273 nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd);
275 #ifdef DEBUG_PASSWORD
276 DEBUG(100,("lm cypher:"));
277 dump_data(100, lm_owf_user_pwd, 16);
279 DEBUG(100,("nt cypher:"));
280 dump_data(100, nt_owf_user_pwd, 16);
283 memcpy(key, cli->dc->sess_key, 8);
285 memcpy(lm_owf, lm_owf_user_pwd, 16);
286 SamOEMhash(lm_owf, key, 16);
287 memcpy(nt_owf, nt_owf_user_pwd, 16);
288 SamOEMhash(nt_owf, key, 16);
290 #ifdef DEBUG_PASSWORD
291 DEBUG(100,("encrypt of lm owf password:"));
292 dump_data(100, lm_owf, 16);
294 DEBUG(100,("encrypt of nt owf password:"));
295 dump_data(100, nt_owf, 16);
297 memcpy(lmpassword.hash, lm_owf, 16);
298 memcpy(ntpassword.hash, nt_owf, 16);
300 init_netr_PasswordInfo(password_info,
310 logon->password = password_info;
314 case NET_LOGON_TYPE: {
315 struct netr_NetworkInfo *network_info;
317 unsigned char local_lm_response[24];
318 unsigned char local_nt_response[24];
319 struct netr_ChallengeResponse lm;
320 struct netr_ChallengeResponse nt;
325 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
327 return NT_STATUS_NO_MEMORY;
330 generate_random_buffer(chal, 8);
332 SMBencrypt(password, chal, local_lm_response);
333 SMBNTencrypt(password, chal, local_nt_response);
336 lm.data = local_lm_response;
339 nt.data = local_nt_response;
341 init_netr_NetworkInfo(network_info,
352 logon->network = network_info;
357 DEBUG(0, ("switch value %d not supported\n",
359 return NT_STATUS_INVALID_INFO_CLASS;
362 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
363 cli->dc->remote_machine,
373 if (memcmp(zeros, &ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
374 /* Check returned credentials if present. */
375 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
376 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
377 return NT_STATUS_ACCESS_DENIED;
386 * Logon domain user with an 'network' SAM logon
388 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
391 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
393 uint32 logon_parameters,
395 const char *username,
397 const char *workstation,
399 DATA_BLOB lm_response,
400 DATA_BLOB nt_response,
401 struct netr_SamInfo3 **info3)
403 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
404 int validation_level = 3;
405 const char *workstation_name_slash;
406 const char *server_name_slash;
408 struct netr_Authenticator clnt_creds;
409 struct netr_Authenticator ret_creds;
410 union netr_LogonLevel *logon = NULL;
411 struct netr_NetworkInfo *network_info;
412 uint8_t authoritative;
413 union netr_Validation validation;
414 struct netr_ChallengeResponse lm;
415 struct netr_ChallengeResponse nt;
416 struct netr_UserSessionKey user_session_key;
417 struct netr_LMSessionKey lmsesskey;
422 ZERO_STRUCT(ret_creds);
427 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
429 return NT_STATUS_NO_MEMORY;
432 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
434 return NT_STATUS_NO_MEMORY;
437 netlogon_creds_client_step(cli->dc, &clnt_creds);
439 if (server[0] != '\\' && server[1] != '\\') {
440 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
442 server_name_slash = server;
445 if (workstation[0] != '\\' && workstation[1] != '\\') {
446 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
448 workstation_name_slash = workstation;
451 if (!workstation_name_slash || !server_name_slash) {
452 DEBUG(0, ("talloc_asprintf failed!\n"));
453 return NT_STATUS_NO_MEMORY;
456 /* Initialise input parameters */
458 lm.data = lm_response.data;
459 lm.length = lm_response.length;
460 nt.data = nt_response.data;
461 nt.length = nt_response.length;
463 init_netr_NetworkInfo(network_info,
469 workstation_name_slash,
474 logon->network = network_info;
476 /* Marshall data and send request */
478 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
488 if (!NT_STATUS_IS_OK(result)) {
492 user_session_key = validation.sam3->base.key;
493 lmsesskey = validation.sam3->base.LMSessKey;
495 if (memcmp(zeros, user_session_key.key, 16) != 0) {
496 SamOEMhash(user_session_key.key, cli->dc->sess_key, 16);
499 if (memcmp(zeros, lmsesskey.key, 8) != 0) {
500 SamOEMhash(lmsesskey.key, cli->dc->sess_key, 8);
503 if (memcmp(zeros, ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
504 /* Check returned credentials if present. */
505 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
506 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
507 return NT_STATUS_ACCESS_DENIED;
511 *info3 = validation.sam3;
516 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
518 uint32 logon_parameters,
520 const char *username,
522 const char *workstation,
524 DATA_BLOB lm_response,
525 DATA_BLOB nt_response,
526 struct netr_SamInfo3 **info3)
528 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
529 int validation_level = 3;
530 const char *workstation_name_slash;
531 const char *server_name_slash;
533 union netr_LogonLevel *logon = NULL;
534 struct netr_NetworkInfo *network_info;
535 uint8_t authoritative;
536 union netr_Validation validation;
537 struct netr_ChallengeResponse lm;
538 struct netr_ChallengeResponse nt;
539 struct netr_UserSessionKey user_session_key;
540 struct netr_LMSessionKey lmsesskey;
550 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
552 return NT_STATUS_NO_MEMORY;
555 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
557 return NT_STATUS_NO_MEMORY;
560 if (server[0] != '\\' && server[1] != '\\') {
561 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
563 server_name_slash = server;
566 if (workstation[0] != '\\' && workstation[1] != '\\') {
567 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
569 workstation_name_slash = workstation;
572 if (!workstation_name_slash || !server_name_slash) {
573 DEBUG(0, ("talloc_asprintf failed!\n"));
574 return NT_STATUS_NO_MEMORY;
577 /* Initialise input parameters */
579 lm.data = lm_response.data;
580 lm.length = lm_response.length;
581 nt.data = nt_response.data;
582 nt.length = nt_response.length;
584 init_netr_NetworkInfo(network_info,
590 workstation_name_slash,
595 logon->network = network_info;
597 /* Marshall data and send request */
599 result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
608 if (!NT_STATUS_IS_OK(result)) {
612 user_session_key = validation.sam3->base.key;
613 lmsesskey = validation.sam3->base.LMSessKey;
615 if (memcmp(zeros, user_session_key.key, 16) != 0) {
616 SamOEMhash(user_session_key.key, cli->dc->sess_key, 16);
619 if (memcmp(zeros, lmsesskey.key, 8) != 0) {
620 SamOEMhash(lmsesskey.key, cli->dc->sess_key, 8);
623 *info3 = validation.sam3;