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.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 /* LSA Request Challenge. Sends our challenge to server, then gets
25 server response. These are used to generate the credentials.
26 The sent and received challenges are stored in the netlog pipe
27 private data. Only call this via rpccli_netlogon_setup_creds(). JRA.
30 /* instead of rpccli_net_req_chal() we use rpccli_netr_ServerReqChallenge() now - gd */
33 /****************************************************************************
36 Send the client credential, receive back a server credential.
37 Ensure that the server credential returned matches the session key
38 encrypt of the server challenge originally received. JRA.
39 ****************************************************************************/
41 NTSTATUS rpccli_net_auth2(struct rpc_pipe_client *cli,
43 uint32 *neg_flags, DOM_CHAL *srv_chal)
45 prs_struct qbuf, rbuf;
48 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
51 if ( sec_chan == SEC_CHAN_DOMAIN )
52 fstr_sprintf( machine_acct, "%s$", lp_workgroup() );
54 fstrcpy( machine_acct, cli->mach_acct );
56 /* create and send a MSRPC command with api NET_AUTH2 */
58 DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
59 cli->srv_name_slash, machine_acct, sec_chan, global_myname(),
60 credstr(cli->clnt_cred.challenge.data), *neg_flags));
62 /* store the parameters */
64 init_q_auth_2(&q, cli->srv_name_slash, machine_acct,
65 sec_chan, global_myname(), &cli->clnt_cred.challenge,
68 /* turn parameters into data stream */
70 CLI_DO_RPC(cli, mem_ctx, PI_NETLOGON, NET_AUTH2,
75 NT_STATUS_UNSUCCESSFUL);
79 if (NT_STATUS_IS_OK(result)) {
83 * Check the returned value using the initial
84 * server received challenge.
88 if (cred_assert( &r.srv_chal, cli->sess_key, srv_chal, zerotime) == 0) {
91 * Server replied with bad credential. Fail.
93 DEBUG(0,("cli_net_auth2: server %s replied with bad credential (bad machine \
94 password ?).\n", cli->cli->desthost ));
95 return NT_STATUS_ACCESS_DENIED;
97 *neg_flags = r.srv_flgs.neg_flags;
104 /****************************************************************************
107 Send the client credential, receive back a server credential.
108 The caller *must* ensure that the server credential returned matches the session key
109 encrypt of the server challenge originally received. JRA.
110 ****************************************************************************/
112 /* instead of rpccli_net_auth2() we use rpccli_netr_ServerAuthenticate2() now - gd */
115 /****************************************************************************
116 Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
117 credentials chain. Stores the credentials in the struct dcinfo in the
118 netlogon pipe struct.
119 ****************************************************************************/
121 NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
122 const char *server_name,
124 const char *clnt_name,
125 const char *machine_account,
126 const unsigned char machine_pwd[16],
127 enum netr_SchannelType sec_chan_type,
128 uint32_t *neg_flags_inout)
130 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
131 struct netr_Credential clnt_chal_send;
132 struct netr_Credential srv_chal_recv;
135 SMB_ASSERT(cli->pipe_idx == PI_NETLOGON);
139 return NT_STATUS_INVALID_PARAMETER;
142 /* Ensure we don't reuse any of this state. */
145 /* Store the machine account password we're going to use. */
146 memcpy(dc->mach_pw, machine_pwd, 16);
148 fstrcpy(dc->remote_machine, "\\\\");
149 fstrcat(dc->remote_machine, server_name);
151 fstrcpy(dc->domain, domain);
153 fstr_sprintf( dc->mach_acct, "%s$", machine_account);
155 /* Create the client challenge. */
156 generate_random_buffer(clnt_chal_send.data, 8);
158 /* Get the server challenge. */
159 result = rpccli_netr_ServerReqChallenge(cli, cli->mem_ctx,
164 if (!NT_STATUS_IS_OK(result)) {
168 /* Calculate the session key and client credentials */
169 creds_client_init(*neg_flags_inout,
177 * Send client auth-2 challenge and receive server repy.
180 result = rpccli_netr_ServerAuthenticate2(cli, cli->mem_ctx,
185 &clnt_chal_send, /* input. */
186 &srv_chal_recv, /* output. */
188 if (!NT_STATUS_IS_OK(result)) {
193 * Check the returned value using the initial
194 * server received challenge.
197 if (!netlogon_creds_client_check(dc, &srv_chal_recv)) {
199 * Server replied with bad credential. Fail.
201 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
202 "replied with bad credential\n",
203 cli->cli->desthost ));
204 return NT_STATUS_ACCESS_DENIED;
207 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
208 "chain established.\n",
209 cli->cli->desthost ));
214 /* Logon domain user */
216 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
218 uint32 logon_parameters,
220 const char *username,
221 const char *password,
222 const char *workstation,
225 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
226 struct netr_Authenticator clnt_creds;
227 struct netr_Authenticator ret_creds;
228 union netr_LogonLevel *logon;
229 union netr_Validation validation;
230 uint8_t authoritative;
231 int validation_level = 3;
232 fstring clnt_name_slash;
235 ZERO_STRUCT(ret_creds);
238 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
240 return NT_STATUS_NO_MEMORY;
244 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
246 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
249 /* Initialise input parameters */
251 netlogon_creds_client_step(cli->dc, &clnt_creds);
253 switch (logon_type) {
254 case INTERACTIVE_LOGON_TYPE: {
256 struct netr_PasswordInfo *password_info;
258 struct samr_Password lmpassword;
259 struct samr_Password ntpassword;
261 unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16];
263 unsigned char lm_owf[16];
264 unsigned char nt_owf[16];
265 unsigned char key[16];
267 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
268 if (!password_info) {
269 return NT_STATUS_NO_MEMORY;
272 nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd);
274 #ifdef DEBUG_PASSWORD
275 DEBUG(100,("lm cypher:"));
276 dump_data(100, lm_owf_user_pwd, 16);
278 DEBUG(100,("nt cypher:"));
279 dump_data(100, nt_owf_user_pwd, 16);
282 memcpy(key, cli->dc->sess_key, 8);
284 memcpy(lm_owf, lm_owf_user_pwd, 16);
285 SamOEMhash(lm_owf, key, 16);
286 memcpy(nt_owf, nt_owf_user_pwd, 16);
287 SamOEMhash(nt_owf, key, 16);
289 #ifdef DEBUG_PASSWORD
290 DEBUG(100,("encrypt of lm owf password:"));
291 dump_data(100, lm_owf, 16);
293 DEBUG(100,("encrypt of nt owf password:"));
294 dump_data(100, nt_owf, 16);
296 memcpy(lmpassword.hash, lm_owf, 16);
297 memcpy(ntpassword.hash, nt_owf, 16);
299 init_netr_PasswordInfo(password_info,
309 logon->password = password_info;
313 case NET_LOGON_TYPE: {
314 struct netr_NetworkInfo *network_info;
316 unsigned char local_lm_response[24];
317 unsigned char local_nt_response[24];
318 struct netr_ChallengeResponse lm;
319 struct netr_ChallengeResponse nt;
324 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
326 return NT_STATUS_NO_MEMORY;
329 generate_random_buffer(chal, 8);
331 SMBencrypt(password, chal, local_lm_response);
332 SMBNTencrypt(password, chal, local_nt_response);
335 lm.data = local_lm_response;
338 nt.data = local_nt_response;
340 init_netr_NetworkInfo(network_info,
351 logon->network = network_info;
356 DEBUG(0, ("switch value %d not supported\n",
358 return NT_STATUS_INVALID_INFO_CLASS;
361 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
362 cli->dc->remote_machine,
372 if (memcmp(zeros, &ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
373 /* Check returned credentials if present. */
374 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
375 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
376 return NT_STATUS_ACCESS_DENIED;
385 * Logon domain user with an 'network' SAM logon
387 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
390 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
392 uint32 logon_parameters,
394 const char *username,
396 const char *workstation,
398 DATA_BLOB lm_response,
399 DATA_BLOB nt_response,
400 struct netr_SamInfo3 **info3)
402 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
403 int validation_level = 3;
404 const char *workstation_name_slash;
405 const char *server_name_slash;
407 struct netr_Authenticator clnt_creds;
408 struct netr_Authenticator ret_creds;
409 union netr_LogonLevel *logon = NULL;
410 struct netr_NetworkInfo *network_info;
411 uint8_t authoritative;
412 union netr_Validation validation;
413 struct netr_ChallengeResponse lm;
414 struct netr_ChallengeResponse nt;
415 struct netr_UserSessionKey user_session_key;
416 struct netr_LMSessionKey lmsesskey;
421 ZERO_STRUCT(ret_creds);
426 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
428 return NT_STATUS_NO_MEMORY;
431 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
433 return NT_STATUS_NO_MEMORY;
436 netlogon_creds_client_step(cli->dc, &clnt_creds);
438 if (server[0] != '\\' && server[1] != '\\') {
439 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
441 server_name_slash = server;
444 if (workstation[0] != '\\' && workstation[1] != '\\') {
445 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
447 workstation_name_slash = workstation;
450 if (!workstation_name_slash || !server_name_slash) {
451 DEBUG(0, ("talloc_asprintf failed!\n"));
452 return NT_STATUS_NO_MEMORY;
455 /* Initialise input parameters */
457 lm.data = lm_response.data;
458 lm.length = lm_response.length;
459 nt.data = nt_response.data;
460 nt.length = nt_response.length;
462 init_netr_NetworkInfo(network_info,
468 workstation_name_slash,
473 logon->network = network_info;
475 /* Marshall data and send request */
477 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
487 if (!NT_STATUS_IS_OK(result)) {
491 user_session_key = validation.sam3->base.key;
492 lmsesskey = validation.sam3->base.LMSessKey;
494 if (memcmp(zeros, user_session_key.key, 16) != 0) {
495 SamOEMhash(user_session_key.key, cli->dc->sess_key, 16);
498 if (memcmp(zeros, lmsesskey.key, 8) != 0) {
499 SamOEMhash(lmsesskey.key, cli->dc->sess_key, 8);
502 if (memcmp(zeros, ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
503 /* Check returned credentials if present. */
504 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
505 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
506 return NT_STATUS_ACCESS_DENIED;
510 *info3 = validation.sam3;
515 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
517 uint32 logon_parameters,
519 const char *username,
521 const char *workstation,
523 DATA_BLOB lm_response,
524 DATA_BLOB nt_response,
525 struct netr_SamInfo3 **info3)
527 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
528 int validation_level = 3;
529 const char *workstation_name_slash;
530 const char *server_name_slash;
532 union netr_LogonLevel *logon = NULL;
533 struct netr_NetworkInfo *network_info;
534 uint8_t authoritative;
535 union netr_Validation validation;
536 struct netr_ChallengeResponse lm;
537 struct netr_ChallengeResponse nt;
538 struct netr_UserSessionKey user_session_key;
539 struct netr_LMSessionKey lmsesskey;
549 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
551 return NT_STATUS_NO_MEMORY;
554 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
556 return NT_STATUS_NO_MEMORY;
559 if (server[0] != '\\' && server[1] != '\\') {
560 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
562 server_name_slash = server;
565 if (workstation[0] != '\\' && workstation[1] != '\\') {
566 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
568 workstation_name_slash = workstation;
571 if (!workstation_name_slash || !server_name_slash) {
572 DEBUG(0, ("talloc_asprintf failed!\n"));
573 return NT_STATUS_NO_MEMORY;
576 /* Initialise input parameters */
578 lm.data = lm_response.data;
579 lm.length = lm_response.length;
580 nt.data = nt_response.data;
581 nt.length = nt_response.length;
583 init_netr_NetworkInfo(network_info,
589 workstation_name_slash,
594 logon->network = network_info;
596 /* Marshall data and send request */
598 result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
607 if (!NT_STATUS_IS_OK(result)) {
611 user_session_key = validation.sam3->base.key;
612 lmsesskey = validation.sam3->base.LMSessKey;
614 if (memcmp(zeros, user_session_key.key, 16) != 0) {
615 SamOEMhash(user_session_key.key, cli->dc->sess_key, 16);
618 if (memcmp(zeros, lmsesskey.key, 8) != 0) {
619 SamOEMhash(lmsesskey.key, cli->dc->sess_key, 8);
622 *info3 = validation.sam3;