Ensure we don't try and cancel anything that is in a compound-related request.
[Samba.git] / source3 / rpc_client / cli_netlogon.c
blobbd3232d2cde4955652ba62b702302f1ddea1c3f7
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"
24 #include "rpc_client/rpc_client.h"
25 #include "../libcli/auth/libcli_auth.h"
26 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
27 #include "rpc_client/cli_netlogon.h"
28 #include "rpc_client/init_netlogon.h"
29 #include "rpc_client/util_netlogon.h"
30 #include "../libcli/security/security.h"
32 /****************************************************************************
33 Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
34 credentials chain. Stores the credentials in the struct dcinfo in the
35 netlogon pipe struct.
36 ****************************************************************************/
38 NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
39 const char *server_name,
40 const char *domain,
41 const char *clnt_name,
42 const char *machine_account,
43 const unsigned char machine_pwd[16],
44 enum netr_SchannelType sec_chan_type,
45 uint32_t *neg_flags_inout)
47 NTSTATUS status;
48 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
49 struct netr_Credential clnt_chal_send;
50 struct netr_Credential srv_chal_recv;
51 struct samr_Password password;
52 bool retried = false;
53 fstring mach_acct;
54 uint32_t neg_flags = *neg_flags_inout;
55 struct dcerpc_binding_handle *b = cli->binding_handle;
57 if (!ndr_syntax_id_equal(&cli->abstract_syntax,
58 &ndr_table_netlogon.syntax_id)) {
59 return NT_STATUS_INVALID_PARAMETER;
62 TALLOC_FREE(cli->dc);
64 /* Store the machine account password we're going to use. */
65 memcpy(password.hash, machine_pwd, 16);
67 fstr_sprintf( mach_acct, "%s$", machine_account);
69 again:
70 /* Create the client challenge. */
71 generate_random_buffer(clnt_chal_send.data, 8);
73 /* Get the server challenge. */
74 status = dcerpc_netr_ServerReqChallenge(b, talloc_tos(),
75 cli->srv_name_slash,
76 clnt_name,
77 &clnt_chal_send,
78 &srv_chal_recv,
79 &result);
80 if (!NT_STATUS_IS_OK(status)) {
81 return status;
83 if (!NT_STATUS_IS_OK(result)) {
84 return result;
87 /* Calculate the session key and client credentials */
89 cli->dc = netlogon_creds_client_init(cli,
90 mach_acct,
91 clnt_name,
92 &clnt_chal_send,
93 &srv_chal_recv,
94 &password,
95 &clnt_chal_send,
96 neg_flags);
98 if (!cli->dc) {
99 return NT_STATUS_NO_MEMORY;
103 * Send client auth-2 challenge and receive server repy.
106 status = dcerpc_netr_ServerAuthenticate2(b, talloc_tos(),
107 cli->srv_name_slash,
108 cli->dc->account_name,
109 sec_chan_type,
110 cli->dc->computer_name,
111 &clnt_chal_send, /* input. */
112 &srv_chal_recv, /* output. */
113 &neg_flags,
114 &result);
115 if (!NT_STATUS_IS_OK(status)) {
116 return status;
118 /* we might be talking to NT4, so let's downgrade in that case and retry
119 * with the returned neg_flags - gd */
121 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
122 retried = true;
123 TALLOC_FREE(cli->dc);
124 goto again;
127 if (!NT_STATUS_IS_OK(result)) {
128 return result;
132 * Check the returned value using the initial
133 * server received challenge.
136 if (!netlogon_creds_client_check(cli->dc, &srv_chal_recv)) {
138 * Server replied with bad credential. Fail.
140 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
141 "replied with bad credential\n",
142 cli->desthost ));
143 return NT_STATUS_ACCESS_DENIED;
146 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
147 "chain established.\n",
148 cli->desthost ));
150 cli->dc->negotiate_flags = neg_flags;
151 *neg_flags_inout = neg_flags;
153 return NT_STATUS_OK;
156 /* Logon domain user */
158 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
159 TALLOC_CTX *mem_ctx,
160 uint32 logon_parameters,
161 const char *domain,
162 const char *username,
163 const char *password,
164 const char *workstation,
165 uint16_t validation_level,
166 int logon_type)
168 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
169 NTSTATUS status;
170 struct netr_Authenticator clnt_creds;
171 struct netr_Authenticator ret_creds;
172 union netr_LogonLevel *logon;
173 union netr_Validation validation;
174 uint8_t authoritative;
175 fstring clnt_name_slash;
176 struct dcerpc_binding_handle *b = cli->binding_handle;
178 ZERO_STRUCT(ret_creds);
180 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
181 if (!logon) {
182 return NT_STATUS_NO_MEMORY;
185 if (workstation) {
186 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
187 } else {
188 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
191 /* Initialise input parameters */
193 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
195 switch (logon_type) {
196 case NetlogonInteractiveInformation: {
198 struct netr_PasswordInfo *password_info;
200 struct samr_Password lmpassword;
201 struct samr_Password ntpassword;
203 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
204 if (!password_info) {
205 return NT_STATUS_NO_MEMORY;
208 nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash);
210 if (cli->dc->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
211 netlogon_creds_arcfour_crypt(cli->dc, lmpassword.hash, 16);
212 netlogon_creds_arcfour_crypt(cli->dc, ntpassword.hash, 16);
213 } else {
214 netlogon_creds_des_encrypt(cli->dc, &lmpassword);
215 netlogon_creds_des_encrypt(cli->dc, &ntpassword);
218 password_info->identity_info.domain_name.string = domain;
219 password_info->identity_info.parameter_control = logon_parameters;
220 password_info->identity_info.logon_id_low = 0xdead;
221 password_info->identity_info.logon_id_high = 0xbeef;
222 password_info->identity_info.account_name.string = username;
223 password_info->identity_info.workstation.string = clnt_name_slash;
225 password_info->lmpassword = lmpassword;
226 password_info->ntpassword = ntpassword;
228 logon->password = password_info;
230 break;
232 case NetlogonNetworkInformation: {
233 struct netr_NetworkInfo *network_info;
234 uint8 chal[8];
235 unsigned char local_lm_response[24];
236 unsigned char local_nt_response[24];
237 struct netr_ChallengeResponse lm;
238 struct netr_ChallengeResponse nt;
240 ZERO_STRUCT(lm);
241 ZERO_STRUCT(nt);
243 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
244 if (!network_info) {
245 return NT_STATUS_NO_MEMORY;
248 generate_random_buffer(chal, 8);
250 SMBencrypt(password, chal, local_lm_response);
251 SMBNTencrypt(password, chal, local_nt_response);
253 lm.length = 24;
254 lm.data = local_lm_response;
256 nt.length = 24;
257 nt.data = local_nt_response;
259 network_info->identity_info.domain_name.string = domain;
260 network_info->identity_info.parameter_control = logon_parameters;
261 network_info->identity_info.logon_id_low = 0xdead;
262 network_info->identity_info.logon_id_high = 0xbeef;
263 network_info->identity_info.account_name.string = username;
264 network_info->identity_info.workstation.string = clnt_name_slash;
266 memcpy(network_info->challenge, chal, 8);
267 network_info->nt = nt;
268 network_info->lm = lm;
270 logon->network = network_info;
272 break;
274 default:
275 DEBUG(0, ("switch value %d not supported\n",
276 logon_type));
277 return NT_STATUS_INVALID_INFO_CLASS;
280 status = dcerpc_netr_LogonSamLogon(b, mem_ctx,
281 cli->srv_name_slash,
282 global_myname(),
283 &clnt_creds,
284 &ret_creds,
285 logon_type,
286 logon,
287 validation_level,
288 &validation,
289 &authoritative,
290 &result);
291 if (!NT_STATUS_IS_OK(status)) {
292 return status;
295 /* Always check returned credentials */
296 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
297 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
298 return NT_STATUS_ACCESS_DENIED;
301 return result;
304 static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
305 uint16_t validation_level,
306 union netr_Validation *validation,
307 struct netr_SamInfo3 **info3_p)
309 struct netr_SamInfo3 *info3;
310 NTSTATUS status;
312 if (validation == NULL) {
313 return NT_STATUS_INVALID_PARAMETER;
316 switch (validation_level) {
317 case 3:
318 if (validation->sam3 == NULL) {
319 return NT_STATUS_INVALID_PARAMETER;
322 info3 = talloc_move(mem_ctx, &validation->sam3);
323 break;
324 case 6:
325 if (validation->sam6 == NULL) {
326 return NT_STATUS_INVALID_PARAMETER;
329 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
330 if (info3 == NULL) {
331 return NT_STATUS_NO_MEMORY;
333 status = copy_netr_SamBaseInfo(info3, &validation->sam6->base, &info3->base);
334 if (!NT_STATUS_IS_OK(status)) {
335 TALLOC_FREE(info3);
336 return status;
339 info3->sidcount = validation->sam6->sidcount;
340 info3->sids = talloc_move(info3, &validation->sam6->sids);
341 break;
342 default:
343 return NT_STATUS_BAD_VALIDATION_CLASS;
346 *info3_p = info3;
348 return NT_STATUS_OK;
352 * Logon domain user with an 'network' SAM logon
354 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
357 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
358 TALLOC_CTX *mem_ctx,
359 uint32 logon_parameters,
360 const char *server,
361 const char *username,
362 const char *domain,
363 const char *workstation,
364 const uint8 chal[8],
365 uint16_t validation_level,
366 DATA_BLOB lm_response,
367 DATA_BLOB nt_response,
368 struct netr_SamInfo3 **info3)
370 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
371 NTSTATUS status;
372 const char *workstation_name_slash;
373 const char *server_name_slash;
374 struct netr_Authenticator clnt_creds;
375 struct netr_Authenticator ret_creds;
376 union netr_LogonLevel *logon = NULL;
377 struct netr_NetworkInfo *network_info;
378 uint8_t authoritative;
379 union netr_Validation validation;
380 struct netr_ChallengeResponse lm;
381 struct netr_ChallengeResponse nt;
382 struct dcerpc_binding_handle *b = cli->binding_handle;
384 *info3 = NULL;
386 ZERO_STRUCT(ret_creds);
388 ZERO_STRUCT(lm);
389 ZERO_STRUCT(nt);
391 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
392 if (!logon) {
393 return NT_STATUS_NO_MEMORY;
396 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
397 if (!network_info) {
398 return NT_STATUS_NO_MEMORY;
401 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
403 if (server[0] != '\\' && server[1] != '\\') {
404 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
405 } else {
406 server_name_slash = server;
409 if (workstation[0] != '\\' && workstation[1] != '\\') {
410 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
411 } else {
412 workstation_name_slash = workstation;
415 if (!workstation_name_slash || !server_name_slash) {
416 DEBUG(0, ("talloc_asprintf failed!\n"));
417 return NT_STATUS_NO_MEMORY;
420 /* Initialise input parameters */
422 lm.data = lm_response.data;
423 lm.length = lm_response.length;
424 nt.data = nt_response.data;
425 nt.length = nt_response.length;
427 network_info->identity_info.domain_name.string = domain;
428 network_info->identity_info.parameter_control = logon_parameters;
429 network_info->identity_info.logon_id_low = 0xdead;
430 network_info->identity_info.logon_id_high = 0xbeef;
431 network_info->identity_info.account_name.string = username;
432 network_info->identity_info.workstation.string = workstation_name_slash;
434 memcpy(network_info->challenge, chal, 8);
435 network_info->nt = nt;
436 network_info->lm = lm;
438 logon->network = network_info;
440 /* Marshall data and send request */
442 status = dcerpc_netr_LogonSamLogon(b, mem_ctx,
443 server_name_slash,
444 global_myname(),
445 &clnt_creds,
446 &ret_creds,
447 NetlogonNetworkInformation,
448 logon,
449 validation_level,
450 &validation,
451 &authoritative,
452 &result);
453 if (!NT_STATUS_IS_OK(status)) {
454 return status;
457 /* Always check returned credentials. */
458 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
459 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
460 return NT_STATUS_ACCESS_DENIED;
463 if (!NT_STATUS_IS_OK(result)) {
464 return result;
467 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
469 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
470 if (!NT_STATUS_IS_OK(result)) {
471 return result;
474 return result;
477 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
478 TALLOC_CTX *mem_ctx,
479 uint32 logon_parameters,
480 const char *server,
481 const char *username,
482 const char *domain,
483 const char *workstation,
484 const uint8 chal[8],
485 uint16_t validation_level,
486 DATA_BLOB lm_response,
487 DATA_BLOB nt_response,
488 struct netr_SamInfo3 **info3)
490 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
491 NTSTATUS status;
492 const char *workstation_name_slash;
493 const char *server_name_slash;
494 union netr_LogonLevel *logon = NULL;
495 struct netr_NetworkInfo *network_info;
496 uint8_t authoritative;
497 union netr_Validation validation;
498 struct netr_ChallengeResponse lm;
499 struct netr_ChallengeResponse nt;
500 uint32_t flags = 0;
501 struct dcerpc_binding_handle *b = cli->binding_handle;
503 *info3 = NULL;
505 ZERO_STRUCT(lm);
506 ZERO_STRUCT(nt);
508 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
509 if (!logon) {
510 return NT_STATUS_NO_MEMORY;
513 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
514 if (!network_info) {
515 return NT_STATUS_NO_MEMORY;
518 if (server[0] != '\\' && server[1] != '\\') {
519 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
520 } else {
521 server_name_slash = server;
524 if (workstation[0] != '\\' && workstation[1] != '\\') {
525 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
526 } else {
527 workstation_name_slash = workstation;
530 if (!workstation_name_slash || !server_name_slash) {
531 DEBUG(0, ("talloc_asprintf failed!\n"));
532 return NT_STATUS_NO_MEMORY;
535 /* Initialise input parameters */
537 lm.data = lm_response.data;
538 lm.length = lm_response.length;
539 nt.data = nt_response.data;
540 nt.length = nt_response.length;
542 network_info->identity_info.domain_name.string = domain;
543 network_info->identity_info.parameter_control = logon_parameters;
544 network_info->identity_info.logon_id_low = 0xdead;
545 network_info->identity_info.logon_id_high = 0xbeef;
546 network_info->identity_info.account_name.string = username;
547 network_info->identity_info.workstation.string = workstation_name_slash;
549 memcpy(network_info->challenge, chal, 8);
550 network_info->nt = nt;
551 network_info->lm = lm;
553 logon->network = network_info;
555 /* Marshall data and send request */
557 status = dcerpc_netr_LogonSamLogonEx(b, mem_ctx,
558 server_name_slash,
559 global_myname(),
560 NetlogonNetworkInformation,
561 logon,
562 validation_level,
563 &validation,
564 &authoritative,
565 &flags,
566 &result);
567 if (!NT_STATUS_IS_OK(status)) {
568 return status;
571 if (!NT_STATUS_IS_OK(result)) {
572 return result;
575 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
577 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
578 if (!NT_STATUS_IS_OK(result)) {
579 return result;
582 return result;
585 /*********************************************************
586 Change the domain password on the PDC.
588 Just changes the password betwen the two values specified.
590 Caller must have the cli connected to the netlogon pipe
591 already.
592 **********************************************************/
594 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
595 TALLOC_CTX *mem_ctx,
596 const char *account_name,
597 const unsigned char orig_trust_passwd_hash[16],
598 const char *new_trust_pwd_cleartext,
599 const unsigned char new_trust_passwd_hash[16],
600 enum netr_SchannelType sec_channel_type)
602 NTSTATUS result, status;
603 struct netr_Authenticator clnt_creds, srv_cred;
604 struct dcerpc_binding_handle *b = cli->binding_handle;
606 if (!cli->dc) {
607 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
608 result = rpccli_netlogon_setup_creds(cli,
609 cli->desthost, /* server name */
610 lp_workgroup(), /* domain */
611 global_myname(), /* client name */
612 account_name, /* machine account name */
613 orig_trust_passwd_hash,
614 sec_channel_type,
615 &neg_flags);
616 if (!NT_STATUS_IS_OK(result)) {
617 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
618 nt_errstr(result)));
619 return result;
623 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
625 if (cli->dc->negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
627 struct netr_CryptPassword new_password;
629 init_netr_CryptPassword(new_trust_pwd_cleartext,
630 cli->dc->session_key,
631 &new_password);
633 status = dcerpc_netr_ServerPasswordSet2(b, mem_ctx,
634 cli->srv_name_slash,
635 cli->dc->account_name,
636 sec_channel_type,
637 cli->dc->computer_name,
638 &clnt_creds,
639 &srv_cred,
640 &new_password,
641 &result);
642 if (!NT_STATUS_IS_OK(status)) {
643 DEBUG(0,("dcerpc_netr_ServerPasswordSet2 failed: %s\n",
644 nt_errstr(status)));
645 return status;
647 } else {
649 struct samr_Password new_password;
650 memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash));
651 netlogon_creds_des_encrypt(cli->dc, &new_password);
653 status = dcerpc_netr_ServerPasswordSet(b, mem_ctx,
654 cli->srv_name_slash,
655 cli->dc->account_name,
656 sec_channel_type,
657 cli->dc->computer_name,
658 &clnt_creds,
659 &srv_cred,
660 &new_password,
661 &result);
662 if (!NT_STATUS_IS_OK(status)) {
663 DEBUG(0,("dcerpc_netr_ServerPasswordSet failed: %s\n",
664 nt_errstr(status)));
665 return status;
669 /* Always check returned credentials. */
670 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
671 DEBUG(0,("credentials chain check failed\n"));
672 return NT_STATUS_ACCESS_DENIED;
675 if (!NT_STATUS_IS_OK(result)) {
676 DEBUG(0,("dcerpc_netr_ServerPasswordSet{2} failed: %s\n",
677 nt_errstr(result)));
678 return result;
681 return result;