Allocate rpc_cli->dc in rpccli_netlogon_setup_creds()
[Samba/gebeck_regimport.git] / source3 / rpc_client / cli_netlogon.c
blob7beaae2e22415ab7e192a4a3bdfe990b233f6a90
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(rpccli_is_pipe_idx(cli, PI_NETLOGON));
139 TALLOC_FREE(cli->dc);
140 cli->dc = talloc_zero(cli, struct dcinfo);
141 if (cli->dc == NULL) {
142 return NT_STATUS_NO_MEMORY;
144 dc = cli->dc;
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 again:
157 /* Create the client challenge. */
158 generate_random_buffer(clnt_chal_send.data, 8);
160 /* Get the server challenge. */
161 result = rpccli_netr_ServerReqChallenge(cli, talloc_tos(),
162 dc->remote_machine,
163 clnt_name,
164 &clnt_chal_send,
165 &srv_chal_recv);
166 if (!NT_STATUS_IS_OK(result)) {
167 return result;
170 /* Calculate the session key and client credentials */
171 creds_client_init(*neg_flags_inout,
173 &clnt_chal_send,
174 &srv_chal_recv,
175 machine_pwd,
176 &clnt_chal_send);
179 * Send client auth-2 challenge and receive server repy.
182 result = rpccli_netr_ServerAuthenticate2(cli, talloc_tos(),
183 dc->remote_machine,
184 dc->mach_acct,
185 sec_chan_type,
186 clnt_name,
187 &clnt_chal_send, /* input. */
188 &srv_chal_recv, /* output. */
189 neg_flags_inout);
191 /* we might be talking to NT4, so let's downgrade in that case and retry
192 * with the returned neg_flags - gd */
194 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
195 retried = true;
196 goto again;
199 if (!NT_STATUS_IS_OK(result)) {
200 return result;
204 * Check the returned value using the initial
205 * server received challenge.
208 if (!netlogon_creds_client_check(dc, &srv_chal_recv)) {
210 * Server replied with bad credential. Fail.
212 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
213 "replied with bad credential\n",
214 cli->desthost ));
215 return NT_STATUS_ACCESS_DENIED;
218 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
219 "chain established.\n",
220 cli->desthost ));
222 return NT_STATUS_OK;
225 /* Logon domain user */
227 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
228 TALLOC_CTX *mem_ctx,
229 uint32 logon_parameters,
230 const char *domain,
231 const char *username,
232 const char *password,
233 const char *workstation,
234 int logon_type)
236 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
237 struct netr_Authenticator clnt_creds;
238 struct netr_Authenticator ret_creds;
239 union netr_LogonInfo *logon;
240 union netr_Validation validation;
241 uint8_t authoritative;
242 int validation_level = 3;
243 fstring clnt_name_slash;
244 uint8 zeros[16];
246 ZERO_STRUCT(ret_creds);
247 ZERO_STRUCT(zeros);
249 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
250 if (!logon) {
251 return NT_STATUS_NO_MEMORY;
254 if (workstation) {
255 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
256 } else {
257 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
260 /* Initialise input parameters */
262 netlogon_creds_client_step(cli->dc, &clnt_creds);
264 switch (logon_type) {
265 case INTERACTIVE_LOGON_TYPE: {
267 struct netr_PasswordInfo *password_info;
269 struct samr_Password lmpassword;
270 struct samr_Password ntpassword;
272 unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16];
274 unsigned char lm_owf[16];
275 unsigned char nt_owf[16];
276 unsigned char key[16];
278 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
279 if (!password_info) {
280 return NT_STATUS_NO_MEMORY;
283 nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd);
285 #ifdef DEBUG_PASSWORD
286 DEBUG(100,("lm cypher:"));
287 dump_data(100, lm_owf_user_pwd, 16);
289 DEBUG(100,("nt cypher:"));
290 dump_data(100, nt_owf_user_pwd, 16);
291 #endif
292 memset(key, 0, 16);
293 memcpy(key, cli->dc->sess_key, 8);
295 memcpy(lm_owf, lm_owf_user_pwd, 16);
296 SamOEMhash(lm_owf, key, 16);
297 memcpy(nt_owf, nt_owf_user_pwd, 16);
298 SamOEMhash(nt_owf, key, 16);
300 #ifdef DEBUG_PASSWORD
301 DEBUG(100,("encrypt of lm owf password:"));
302 dump_data(100, lm_owf, 16);
304 DEBUG(100,("encrypt of nt owf password:"));
305 dump_data(100, nt_owf, 16);
306 #endif
307 memcpy(lmpassword.hash, lm_owf, 16);
308 memcpy(ntpassword.hash, nt_owf, 16);
310 init_netr_PasswordInfo(password_info,
311 domain,
312 logon_parameters,
313 0xdead,
314 0xbeef,
315 username,
316 clnt_name_slash,
317 lmpassword,
318 ntpassword);
320 logon->password = password_info;
322 break;
324 case NET_LOGON_TYPE: {
325 struct netr_NetworkInfo *network_info;
326 uint8 chal[8];
327 unsigned char local_lm_response[24];
328 unsigned char local_nt_response[24];
329 struct netr_ChallengeResponse lm;
330 struct netr_ChallengeResponse nt;
332 ZERO_STRUCT(lm);
333 ZERO_STRUCT(nt);
335 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
336 if (!network_info) {
337 return NT_STATUS_NO_MEMORY;
340 generate_random_buffer(chal, 8);
342 SMBencrypt(password, chal, local_lm_response);
343 SMBNTencrypt(password, chal, local_nt_response);
345 lm.length = 24;
346 lm.data = local_lm_response;
348 nt.length = 24;
349 nt.data = local_nt_response;
351 init_netr_NetworkInfo(network_info,
352 domain,
353 logon_parameters,
354 0xdead,
355 0xbeef,
356 username,
357 clnt_name_slash,
358 chal,
360 lm);
362 logon->network = network_info;
364 break;
366 default:
367 DEBUG(0, ("switch value %d not supported\n",
368 logon_type));
369 return NT_STATUS_INVALID_INFO_CLASS;
372 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
373 cli->dc->remote_machine,
374 global_myname(),
375 &clnt_creds,
376 &ret_creds,
377 logon_type,
378 logon,
379 validation_level,
380 &validation,
381 &authoritative);
383 if (memcmp(zeros, &ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
384 /* Check returned credentials if present. */
385 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
386 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
387 return NT_STATUS_ACCESS_DENIED;
391 return result;
396 * Logon domain user with an 'network' SAM logon
398 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
401 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
402 TALLOC_CTX *mem_ctx,
403 uint32 logon_parameters,
404 const char *server,
405 const char *username,
406 const char *domain,
407 const char *workstation,
408 const uint8 chal[8],
409 DATA_BLOB lm_response,
410 DATA_BLOB nt_response,
411 struct netr_SamInfo3 **info3)
413 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
414 int validation_level = 3;
415 const char *workstation_name_slash;
416 const char *server_name_slash;
417 uint8 zeros[16];
418 struct netr_Authenticator clnt_creds;
419 struct netr_Authenticator ret_creds;
420 union netr_LogonInfo *logon = NULL;
421 struct netr_NetworkInfo *network_info;
422 uint8_t authoritative;
423 union netr_Validation validation;
424 struct netr_ChallengeResponse lm;
425 struct netr_ChallengeResponse nt;
426 struct netr_UserSessionKey user_session_key;
427 struct netr_LMSessionKey lmsesskey;
429 *info3 = NULL;
431 ZERO_STRUCT(zeros);
432 ZERO_STRUCT(ret_creds);
434 ZERO_STRUCT(lm);
435 ZERO_STRUCT(nt);
437 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
438 if (!logon) {
439 return NT_STATUS_NO_MEMORY;
442 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
443 if (!network_info) {
444 return NT_STATUS_NO_MEMORY;
447 netlogon_creds_client_step(cli->dc, &clnt_creds);
449 if (server[0] != '\\' && server[1] != '\\') {
450 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
451 } else {
452 server_name_slash = server;
455 if (workstation[0] != '\\' && workstation[1] != '\\') {
456 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
457 } else {
458 workstation_name_slash = workstation;
461 if (!workstation_name_slash || !server_name_slash) {
462 DEBUG(0, ("talloc_asprintf failed!\n"));
463 return NT_STATUS_NO_MEMORY;
466 /* Initialise input parameters */
468 lm.data = lm_response.data;
469 lm.length = lm_response.length;
470 nt.data = nt_response.data;
471 nt.length = nt_response.length;
473 init_netr_NetworkInfo(network_info,
474 domain,
475 logon_parameters,
476 0xdead,
477 0xbeef,
478 username,
479 workstation_name_slash,
480 (uint8_t *) chal,
482 lm);
484 logon->network = network_info;
486 /* Marshall data and send request */
488 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
489 server_name_slash,
490 global_myname(),
491 &clnt_creds,
492 &ret_creds,
493 NET_LOGON_TYPE,
494 logon,
495 validation_level,
496 &validation,
497 &authoritative);
498 if (!NT_STATUS_IS_OK(result)) {
499 return result;
502 user_session_key = validation.sam3->base.key;
503 lmsesskey = validation.sam3->base.LMSessKey;
505 if (memcmp(zeros, user_session_key.key, 16) != 0) {
506 SamOEMhash(user_session_key.key, cli->dc->sess_key, 16);
509 if (memcmp(zeros, lmsesskey.key, 8) != 0) {
510 SamOEMhash(lmsesskey.key, cli->dc->sess_key, 8);
513 if (memcmp(zeros, ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
514 /* Check returned credentials if present. */
515 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
516 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
517 return NT_STATUS_ACCESS_DENIED;
521 *info3 = validation.sam3;
523 return result;
526 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
527 TALLOC_CTX *mem_ctx,
528 uint32 logon_parameters,
529 const char *server,
530 const char *username,
531 const char *domain,
532 const char *workstation,
533 const uint8 chal[8],
534 DATA_BLOB lm_response,
535 DATA_BLOB nt_response,
536 struct netr_SamInfo3 **info3)
538 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
539 int validation_level = 3;
540 const char *workstation_name_slash;
541 const char *server_name_slash;
542 uint8 zeros[16];
543 union netr_LogonInfo *logon = NULL;
544 struct netr_NetworkInfo *network_info;
545 uint8_t authoritative;
546 union netr_Validation validation;
547 struct netr_ChallengeResponse lm;
548 struct netr_ChallengeResponse nt;
549 struct netr_UserSessionKey user_session_key;
550 struct netr_LMSessionKey lmsesskey;
551 uint32_t flags = 0;
553 *info3 = NULL;
555 ZERO_STRUCT(zeros);
557 ZERO_STRUCT(lm);
558 ZERO_STRUCT(nt);
560 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
561 if (!logon) {
562 return NT_STATUS_NO_MEMORY;
565 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
566 if (!network_info) {
567 return NT_STATUS_NO_MEMORY;
570 if (server[0] != '\\' && server[1] != '\\') {
571 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
572 } else {
573 server_name_slash = server;
576 if (workstation[0] != '\\' && workstation[1] != '\\') {
577 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
578 } else {
579 workstation_name_slash = workstation;
582 if (!workstation_name_slash || !server_name_slash) {
583 DEBUG(0, ("talloc_asprintf failed!\n"));
584 return NT_STATUS_NO_MEMORY;
587 /* Initialise input parameters */
589 lm.data = lm_response.data;
590 lm.length = lm_response.length;
591 nt.data = nt_response.data;
592 nt.length = nt_response.length;
594 init_netr_NetworkInfo(network_info,
595 domain,
596 logon_parameters,
597 0xdead,
598 0xbeef,
599 username,
600 workstation_name_slash,
601 (uint8_t *) chal,
603 lm);
605 logon->network = network_info;
607 /* Marshall data and send request */
609 result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
610 server_name_slash,
611 global_myname(),
612 NET_LOGON_TYPE,
613 logon,
614 validation_level,
615 &validation,
616 &authoritative,
617 &flags);
618 if (!NT_STATUS_IS_OK(result)) {
619 return result;
622 user_session_key = validation.sam3->base.key;
623 lmsesskey = validation.sam3->base.LMSessKey;
625 if (memcmp(zeros, user_session_key.key, 16) != 0) {
626 SamOEMhash(user_session_key.key, cli->dc->sess_key, 16);
629 if (memcmp(zeros, lmsesskey.key, 8) != 0) {
630 SamOEMhash(lmsesskey.key, cli->dc->sess_key, 8);
633 *info3 = validation.sam3;
635 return result;