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 #if 0 /* not currebntly used */
116 /****************************************************************************
119 Send the client credential, receive back a server credential.
120 The caller *must* ensure that the server credential returned matches the session key
121 encrypt of the server challenge originally received. JRA.
122 ****************************************************************************/
124 static NTSTATUS rpccli_net_auth3(struct rpc_pipe_client *cli,
126 const char *server_name,
127 const char *account_name,
128 uint16 sec_chan_type,
129 const char *computer_name,
130 uint32 *neg_flags_inout,
131 const DOM_CHAL *clnt_chal_in,
132 DOM_CHAL *srv_chal_out)
134 prs_struct qbuf, rbuf;
137 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
139 /* create and send a MSRPC command with api NET_AUTH2 */
141 DEBUG(4,("cli_net_auth3: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
142 server_name, account_name, sec_chan_type, computer_name,
143 credstr(clnt_chal_in->data), *neg_flags_inout));
145 /* store the parameters */
146 init_q_auth_3(&q, server_name, account_name, sec_chan_type,
147 computer_name, clnt_chal_in, *neg_flags_inout);
149 /* turn parameters into data stream */
151 CLI_DO_RPC(cli, mem_ctx, PI_NETLOGON, NET_AUTH3,
156 NT_STATUS_UNSUCCESSFUL);
158 if (NT_STATUS_IS_OK(result)) {
159 *srv_chal_out = r.srv_chal;
160 *neg_flags_inout = r.srv_flgs.neg_flags;
165 #endif /* not currebntly used */
167 /****************************************************************************
168 Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
169 credentials chain. Stores the credentials in the struct dcinfo in the
170 netlogon pipe struct.
171 ****************************************************************************/
173 NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
174 const char *server_name,
176 const char *clnt_name,
177 const char *machine_account,
178 const unsigned char machine_pwd[16],
179 enum netr_SchannelType sec_chan_type,
180 uint32_t *neg_flags_inout)
182 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
183 struct netr_Credential clnt_chal_send;
184 struct netr_Credential srv_chal_recv;
187 SMB_ASSERT(cli->pipe_idx == PI_NETLOGON);
191 return NT_STATUS_INVALID_PARAMETER;
194 /* Ensure we don't reuse any of this state. */
197 /* Store the machine account password we're going to use. */
198 memcpy(dc->mach_pw, machine_pwd, 16);
200 fstrcpy(dc->remote_machine, "\\\\");
201 fstrcat(dc->remote_machine, server_name);
203 fstrcpy(dc->domain, domain);
205 fstr_sprintf( dc->mach_acct, "%s$", machine_account);
207 /* Create the client challenge. */
208 generate_random_buffer(clnt_chal_send.data, 8);
210 /* Get the server challenge. */
211 result = rpccli_netr_ServerReqChallenge(cli, cli->mem_ctx,
216 if (!NT_STATUS_IS_OK(result)) {
220 /* Calculate the session key and client credentials */
221 creds_client_init(*neg_flags_inout,
229 * Send client auth-2 challenge and receive server repy.
232 result = rpccli_netr_ServerAuthenticate2(cli, cli->mem_ctx,
237 &clnt_chal_send, /* input. */
238 &srv_chal_recv, /* output. */
240 if (!NT_STATUS_IS_OK(result)) {
245 * Check the returned value using the initial
246 * server received challenge.
249 if (!netlogon_creds_client_check(dc, &srv_chal_recv)) {
251 * Server replied with bad credential. Fail.
253 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
254 "replied with bad credential\n",
255 cli->cli->desthost ));
256 return NT_STATUS_ACCESS_DENIED;
259 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
260 "chain established.\n",
261 cli->cli->desthost ));
266 /* Logon domain user */
268 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
270 uint32 logon_parameters,
272 const char *username,
273 const char *password,
274 const char *workstation,
277 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
278 struct netr_Authenticator clnt_creds;
279 struct netr_Authenticator ret_creds;
280 union netr_LogonLevel *logon;
281 union netr_Validation validation;
282 uint8_t authoritative;
283 int validation_level = 3;
284 fstring clnt_name_slash;
287 ZERO_STRUCT(ret_creds);
290 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
292 return NT_STATUS_NO_MEMORY;
296 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
298 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
301 /* Initialise input parameters */
303 netlogon_creds_client_step(cli->dc, &clnt_creds);
305 switch (logon_type) {
306 case INTERACTIVE_LOGON_TYPE: {
308 struct netr_PasswordInfo *password_info;
310 struct samr_Password lmpassword;
311 struct samr_Password ntpassword;
313 unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16];
315 unsigned char lm_owf[16];
316 unsigned char nt_owf[16];
317 unsigned char key[16];
319 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
320 if (!password_info) {
321 return NT_STATUS_NO_MEMORY;
324 nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd);
326 #ifdef DEBUG_PASSWORD
327 DEBUG(100,("lm cypher:"));
328 dump_data(100, lm_owf_user_pwd, 16);
330 DEBUG(100,("nt cypher:"));
331 dump_data(100, nt_owf_user_pwd, 16);
334 memcpy(key, cli->dc->sess_key, 8);
336 memcpy(lm_owf, lm_owf_user_pwd, 16);
337 SamOEMhash(lm_owf, key, 16);
338 memcpy(nt_owf, nt_owf_user_pwd, 16);
339 SamOEMhash(nt_owf, key, 16);
341 #ifdef DEBUG_PASSWORD
342 DEBUG(100,("encrypt of lm owf password:"));
343 dump_data(100, lm_owf, 16);
345 DEBUG(100,("encrypt of nt owf password:"));
346 dump_data(100, nt_owf, 16);
348 memcpy(lmpassword.hash, lm_owf, 16);
349 memcpy(ntpassword.hash, nt_owf, 16);
351 init_netr_PasswordInfo(password_info,
361 logon->password = password_info;
365 case NET_LOGON_TYPE: {
366 struct netr_NetworkInfo *network_info;
368 unsigned char local_lm_response[24];
369 unsigned char local_nt_response[24];
370 struct netr_ChallengeResponse lm;
371 struct netr_ChallengeResponse nt;
373 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
375 return NT_STATUS_NO_MEMORY;
378 generate_random_buffer(chal, 8);
380 SMBencrypt(password, chal, local_lm_response);
381 SMBNTencrypt(password, chal, local_nt_response);
384 lm.data = local_lm_response;
387 nt.data = local_nt_response;
389 init_netr_NetworkInfo(network_info,
400 logon->network = network_info;
405 DEBUG(0, ("switch value %d not supported\n",
407 return NT_STATUS_INVALID_INFO_CLASS;
410 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
411 cli->dc->remote_machine,
421 if (memcmp(zeros, &ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
422 /* Check returned credentials if present. */
423 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
424 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
425 return NT_STATUS_ACCESS_DENIED;
434 * Logon domain user with an 'network' SAM logon
436 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
439 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
441 uint32 logon_parameters,
443 const char *username,
445 const char *workstation,
447 DATA_BLOB lm_response,
448 DATA_BLOB nt_response,
449 struct netr_SamInfo3 **info3)
451 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
452 int validation_level = 3;
453 const char *workstation_name_slash;
454 const char *server_name_slash;
456 struct netr_Authenticator clnt_creds;
457 struct netr_Authenticator ret_creds;
458 union netr_LogonLevel *logon = NULL;
459 struct netr_NetworkInfo *network_info;
460 uint8_t authoritative;
461 union netr_Validation validation;
462 struct netr_ChallengeResponse lm;
463 struct netr_ChallengeResponse nt;
464 struct netr_UserSessionKey user_session_key;
465 struct netr_LMSessionKey lmsesskey;
470 ZERO_STRUCT(ret_creds);
472 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
474 return NT_STATUS_NO_MEMORY;
477 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
479 return NT_STATUS_NO_MEMORY;
482 netlogon_creds_client_step(cli->dc, &clnt_creds);
484 if (server[0] != '\\' && server[1] != '\\') {
485 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
487 server_name_slash = server;
490 if (workstation[0] != '\\' && workstation[1] != '\\') {
491 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
493 workstation_name_slash = workstation;
496 if (!workstation_name_slash || !server_name_slash) {
497 DEBUG(0, ("talloc_asprintf failed!\n"));
498 return NT_STATUS_NO_MEMORY;
501 /* Initialise input parameters */
503 lm.data = lm_response.data;
504 lm.length = lm_response.length;
505 nt.data = nt_response.data;
506 nt.length = nt_response.length;
508 init_netr_NetworkInfo(network_info,
514 workstation_name_slash,
519 logon->network = network_info;
521 /* Marshall data and send request */
523 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
533 if (!NT_STATUS_IS_OK(result)) {
537 user_session_key = validation.sam3->base.key;
538 lmsesskey = validation.sam3->base.LMSessKey;
540 if (memcmp(zeros, user_session_key.key, 16) != 0) {
541 SamOEMhash(user_session_key.key, cli->dc->sess_key, 16);
544 if (memcmp(zeros, lmsesskey.key, 8) != 0) {
545 SamOEMhash(lmsesskey.key, cli->dc->sess_key, 8);
548 if (memcmp(zeros, ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
549 /* Check returned credentials if present. */
550 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
551 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
552 return NT_STATUS_ACCESS_DENIED;
556 *info3 = validation.sam3;
561 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
563 uint32 logon_parameters,
565 const char *username,
567 const char *workstation,
569 DATA_BLOB lm_response,
570 DATA_BLOB nt_response,
571 NET_USER_INFO_3 *info3)
573 prs_struct qbuf, rbuf;
574 NET_Q_SAM_LOGON_EX q;
575 NET_R_SAM_LOGON_EX r;
576 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
578 int validation_level = 3;
579 const char *workstation_name_slash;
580 const char *server_name_slash;
588 if (server[0] != '\\' && server[1] != '\\') {
589 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
591 server_name_slash = server;
594 if (workstation[0] != '\\' && workstation[1] != '\\') {
595 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
597 workstation_name_slash = workstation;
600 if (!workstation_name_slash || !server_name_slash) {
601 DEBUG(0, ("talloc_asprintf failed!\n"));
602 return NT_STATUS_NO_MEMORY;
605 /* Initialise input parameters */
607 q.validation_level = validation_level;
609 ctr.switch_value = NET_LOGON_TYPE;
611 init_id_info2(&ctr.auth.id2, domain,
612 logon_parameters, /* param_ctrl */
613 0xdead, 0xbeef, /* LUID? */
614 username, workstation_name_slash, (const uchar*)chal,
615 lm_response.data, lm_response.length, nt_response.data,
618 init_sam_info_ex(&q.sam_id, server_name_slash, global_myname(),
619 NET_LOGON_TYPE, &ctr);
623 /* Marshall data and send request */
625 CLI_DO_RPC(cli, mem_ctx, PI_NETLOGON, NET_SAMLOGON_EX,
627 net_io_q_sam_logon_ex,
628 net_io_r_sam_logon_ex,
629 NT_STATUS_UNSUCCESSFUL);
631 if (memcmp(zeros, info3->user_sess_key, 16) != 0) {
632 SamOEMhash(info3->user_sess_key, cli->dc->sess_key, 16);
634 memset(info3->user_sess_key, '\0', 16);
637 if (memcmp(zeros, info3->lm_sess_key, 8) != 0) {
638 SamOEMhash(info3->lm_sess_key, cli->dc->sess_key, 8);
640 memset(info3->lm_sess_key, '\0', 8);
643 for (i=0; i < 7; i++) {
644 memset(&info3->unknown[i], '\0', 4);