Fix typo.
[Samba.git] / source / rpc_client / cli_netlogon.c
blob851a4a8da825285befa304cfe822feef2cb13fa6
1 /*
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/>.
23 #include "includes.h"
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 */
33 #if 0
34 /****************************************************************************
35 LSA Authenticate 2
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,
43 uint16 sec_chan,
44 uint32 *neg_flags, DOM_CHAL *srv_chal)
46 prs_struct qbuf, rbuf;
47 NET_Q_AUTH_2 q;
48 NET_R_AUTH_2 r;
49 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
50 fstring machine_acct;
52 if ( sec_chan == SEC_CHAN_DOMAIN )
53 fstr_sprintf( machine_acct, "%s$", lp_workgroup() );
54 else
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,
67 *neg_flags);
69 /* turn parameters into data stream */
71 CLI_DO_RPC(cli, mem_ctx, PI_NETLOGON, NET_AUTH2,
72 q, r,
73 qbuf, rbuf,
74 net_io_q_auth_2,
75 net_io_r_auth_2,
76 NT_STATUS_UNSUCCESSFUL);
78 result = r.status;
80 if (NT_STATUS_IS_OK(result)) {
81 UTIME zerotime;
84 * Check the returned value using the initial
85 * server received challenge.
88 zerotime.time = 0;
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;
101 return result;
103 #endif
105 /****************************************************************************
106 LSA Authenticate 2
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,
124 const char *domain,
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;
134 struct dcinfo *dc;
135 bool retried = false;
137 SMB_ASSERT(cli->pipe_idx == PI_NETLOGON);
139 dc = cli->dc;
140 if (!dc) {
141 return NT_STATUS_INVALID_PARAMETER;
144 /* Ensure we don't reuse any of this state. */
145 ZERO_STRUCTP(dc);
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);
157 again:
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, cli->mem_ctx,
163 dc->remote_machine,
164 clnt_name,
165 &clnt_chal_send,
166 &srv_chal_recv);
167 if (!NT_STATUS_IS_OK(result)) {
168 return result;
171 /* Calculate the session key and client credentials */
172 creds_client_init(*neg_flags_inout,
174 &clnt_chal_send,
175 &srv_chal_recv,
176 machine_pwd,
177 &clnt_chal_send);
180 * Send client auth-2 challenge and receive server repy.
183 result = rpccli_netr_ServerAuthenticate2(cli, cli->mem_ctx,
184 dc->remote_machine,
185 dc->mach_acct,
186 sec_chan_type,
187 clnt_name,
188 &clnt_chal_send, /* input. */
189 &srv_chal_recv, /* output. */
190 neg_flags_inout);
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) {
196 retried = true;
197 goto again;
200 if (!NT_STATUS_IS_OK(result)) {
201 return 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",
215 cli->cli->desthost ));
216 return NT_STATUS_ACCESS_DENIED;
219 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
220 "chain established.\n",
221 cli->cli->desthost ));
223 return NT_STATUS_OK;
226 /* Logon domain user */
228 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
229 TALLOC_CTX *mem_ctx,
230 uint32 logon_parameters,
231 const char *domain,
232 const char *username,
233 const char *password,
234 const char *workstation,
235 int logon_type)
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;
245 uint8 zeros[16];
247 ZERO_STRUCT(ret_creds);
248 ZERO_STRUCT(zeros);
250 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
251 if (!logon) {
252 return NT_STATUS_NO_MEMORY;
255 if (workstation) {
256 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
257 } else {
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);
292 #endif
293 memset(key, 0, 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);
307 #endif
308 memcpy(lmpassword.hash, lm_owf, 16);
309 memcpy(ntpassword.hash, nt_owf, 16);
311 init_netr_PasswordInfo(password_info,
312 domain,
313 logon_parameters,
314 0xdead,
315 0xbeef,
316 username,
317 clnt_name_slash,
318 lmpassword,
319 ntpassword);
321 logon->password = password_info;
323 break;
325 case NET_LOGON_TYPE: {
326 struct netr_NetworkInfo *network_info;
327 uint8 chal[8];
328 unsigned char local_lm_response[24];
329 unsigned char local_nt_response[24];
330 struct netr_ChallengeResponse lm;
331 struct netr_ChallengeResponse nt;
333 ZERO_STRUCT(lm);
334 ZERO_STRUCT(nt);
336 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
337 if (!network_info) {
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);
346 lm.length = 24;
347 lm.data = local_lm_response;
349 nt.length = 24;
350 nt.data = local_nt_response;
352 init_netr_NetworkInfo(network_info,
353 domain,
354 logon_parameters,
355 0xdead,
356 0xbeef,
357 username,
358 clnt_name_slash,
359 chal,
361 lm);
363 logon->network = network_info;
365 break;
367 default:
368 DEBUG(0, ("switch value %d not supported\n",
369 logon_type));
370 return NT_STATUS_INVALID_INFO_CLASS;
373 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
374 cli->dc->remote_machine,
375 global_myname(),
376 &clnt_creds,
377 &ret_creds,
378 logon_type,
379 logon,
380 validation_level,
381 &validation,
382 &authoritative);
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;
392 return result;
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,
403 TALLOC_CTX *mem_ctx,
404 uint32 logon_parameters,
405 const char *server,
406 const char *username,
407 const char *domain,
408 const char *workstation,
409 const uint8 chal[8],
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;
418 uint8 zeros[16];
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;
430 *info3 = NULL;
432 ZERO_STRUCT(zeros);
433 ZERO_STRUCT(ret_creds);
435 ZERO_STRUCT(lm);
436 ZERO_STRUCT(nt);
438 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
439 if (!logon) {
440 return NT_STATUS_NO_MEMORY;
443 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
444 if (!network_info) {
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);
452 } else {
453 server_name_slash = server;
456 if (workstation[0] != '\\' && workstation[1] != '\\') {
457 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
458 } else {
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,
475 domain,
476 logon_parameters,
477 0xdead,
478 0xbeef,
479 username,
480 workstation_name_slash,
481 (uint8_t *) chal,
483 lm);
485 logon->network = network_info;
487 /* Marshall data and send request */
489 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
490 server_name_slash,
491 global_myname(),
492 &clnt_creds,
493 &ret_creds,
494 NET_LOGON_TYPE,
495 logon,
496 validation_level,
497 &validation,
498 &authoritative);
499 if (!NT_STATUS_IS_OK(result)) {
500 return 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;
524 return result;
527 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
528 TALLOC_CTX *mem_ctx,
529 uint32 logon_parameters,
530 const char *server,
531 const char *username,
532 const char *domain,
533 const char *workstation,
534 const uint8 chal[8],
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;
543 uint8 zeros[16];
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;
552 uint32_t flags = 0;
554 *info3 = NULL;
556 ZERO_STRUCT(zeros);
558 ZERO_STRUCT(lm);
559 ZERO_STRUCT(nt);
561 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
562 if (!logon) {
563 return NT_STATUS_NO_MEMORY;
566 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
567 if (!network_info) {
568 return NT_STATUS_NO_MEMORY;
571 if (server[0] != '\\' && server[1] != '\\') {
572 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
573 } else {
574 server_name_slash = server;
577 if (workstation[0] != '\\' && workstation[1] != '\\') {
578 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
579 } else {
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,
596 domain,
597 logon_parameters,
598 0xdead,
599 0xbeef,
600 username,
601 workstation_name_slash,
602 (uint8_t *) chal,
604 lm);
606 logon->network = network_info;
608 /* Marshall data and send request */
610 result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
611 server_name_slash,
612 global_myname(),
613 NET_LOGON_TYPE,
614 logon,
615 validation_level,
616 &validation,
617 &authoritative,
618 &flags);
619 if (!NT_STATUS_IS_OK(result)) {
620 return 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;
636 return result;