libcli/auth: support AES decryption in netlogon_creds_decrypt_samlogon().
[Samba/gebeck_regimport.git] / source3 / rpc_client / cli_netlogon.c
bloba0a94578beac4979be33fcd5315e454971bf5d46
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(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", lp_netbios_name() );
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(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_SUPPORTS_AES) {
211 netlogon_creds_aes_encrypt(cli->dc, lmpassword.hash, 16);
212 netlogon_creds_aes_encrypt(cli->dc, ntpassword.hash, 16);
213 } else if (cli->dc->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
214 netlogon_creds_arcfour_crypt(cli->dc, lmpassword.hash, 16);
215 netlogon_creds_arcfour_crypt(cli->dc, ntpassword.hash, 16);
216 } else {
217 netlogon_creds_des_encrypt(cli->dc, &lmpassword);
218 netlogon_creds_des_encrypt(cli->dc, &ntpassword);
221 password_info->identity_info.domain_name.string = domain;
222 password_info->identity_info.parameter_control = logon_parameters;
223 password_info->identity_info.logon_id_low = 0xdead;
224 password_info->identity_info.logon_id_high = 0xbeef;
225 password_info->identity_info.account_name.string = username;
226 password_info->identity_info.workstation.string = clnt_name_slash;
228 password_info->lmpassword = lmpassword;
229 password_info->ntpassword = ntpassword;
231 logon->password = password_info;
233 break;
235 case NetlogonNetworkInformation: {
236 struct netr_NetworkInfo *network_info;
237 uint8 chal[8];
238 unsigned char local_lm_response[24];
239 unsigned char local_nt_response[24];
240 struct netr_ChallengeResponse lm;
241 struct netr_ChallengeResponse nt;
243 ZERO_STRUCT(lm);
244 ZERO_STRUCT(nt);
246 network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo);
247 if (!network_info) {
248 return NT_STATUS_NO_MEMORY;
251 generate_random_buffer(chal, 8);
253 SMBencrypt(password, chal, local_lm_response);
254 SMBNTencrypt(password, chal, local_nt_response);
256 lm.length = 24;
257 lm.data = local_lm_response;
259 nt.length = 24;
260 nt.data = local_nt_response;
262 network_info->identity_info.domain_name.string = domain;
263 network_info->identity_info.parameter_control = logon_parameters;
264 network_info->identity_info.logon_id_low = 0xdead;
265 network_info->identity_info.logon_id_high = 0xbeef;
266 network_info->identity_info.account_name.string = username;
267 network_info->identity_info.workstation.string = clnt_name_slash;
269 memcpy(network_info->challenge, chal, 8);
270 network_info->nt = nt;
271 network_info->lm = lm;
273 logon->network = network_info;
275 break;
277 default:
278 DEBUG(0, ("switch value %d not supported\n",
279 logon_type));
280 return NT_STATUS_INVALID_INFO_CLASS;
283 status = dcerpc_netr_LogonSamLogon(b, mem_ctx,
284 cli->srv_name_slash,
285 lp_netbios_name(),
286 &clnt_creds,
287 &ret_creds,
288 logon_type,
289 logon,
290 validation_level,
291 &validation,
292 &authoritative,
293 &result);
294 if (!NT_STATUS_IS_OK(status)) {
295 return status;
298 /* Always check returned credentials */
299 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
300 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
301 return NT_STATUS_ACCESS_DENIED;
304 return result;
307 static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
308 uint16_t validation_level,
309 union netr_Validation *validation,
310 struct netr_SamInfo3 **info3_p)
312 struct netr_SamInfo3 *info3;
313 NTSTATUS status;
315 if (validation == NULL) {
316 return NT_STATUS_INVALID_PARAMETER;
319 switch (validation_level) {
320 case 3:
321 if (validation->sam3 == NULL) {
322 return NT_STATUS_INVALID_PARAMETER;
325 info3 = talloc_move(mem_ctx, &validation->sam3);
326 break;
327 case 6:
328 if (validation->sam6 == NULL) {
329 return NT_STATUS_INVALID_PARAMETER;
332 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
333 if (info3 == NULL) {
334 return NT_STATUS_NO_MEMORY;
336 status = copy_netr_SamBaseInfo(info3, &validation->sam6->base, &info3->base);
337 if (!NT_STATUS_IS_OK(status)) {
338 TALLOC_FREE(info3);
339 return status;
342 info3->sidcount = validation->sam6->sidcount;
343 info3->sids = talloc_move(info3, &validation->sam6->sids);
344 break;
345 default:
346 return NT_STATUS_BAD_VALIDATION_CLASS;
349 *info3_p = info3;
351 return NT_STATUS_OK;
355 * Logon domain user with an 'network' SAM logon
357 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
360 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
361 TALLOC_CTX *mem_ctx,
362 uint32 logon_parameters,
363 const char *server,
364 const char *username,
365 const char *domain,
366 const char *workstation,
367 const uint8 chal[8],
368 uint16_t validation_level,
369 DATA_BLOB lm_response,
370 DATA_BLOB nt_response,
371 struct netr_SamInfo3 **info3)
373 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
374 NTSTATUS status;
375 const char *workstation_name_slash;
376 const char *server_name_slash;
377 struct netr_Authenticator clnt_creds;
378 struct netr_Authenticator ret_creds;
379 union netr_LogonLevel *logon = NULL;
380 struct netr_NetworkInfo *network_info;
381 uint8_t authoritative;
382 union netr_Validation validation;
383 struct netr_ChallengeResponse lm;
384 struct netr_ChallengeResponse nt;
385 struct dcerpc_binding_handle *b = cli->binding_handle;
387 *info3 = NULL;
389 ZERO_STRUCT(ret_creds);
391 ZERO_STRUCT(lm);
392 ZERO_STRUCT(nt);
394 logon = talloc_zero(mem_ctx, union netr_LogonLevel);
395 if (!logon) {
396 return NT_STATUS_NO_MEMORY;
399 network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo);
400 if (!network_info) {
401 return NT_STATUS_NO_MEMORY;
404 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
406 if (server[0] != '\\' && server[1] != '\\') {
407 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
408 } else {
409 server_name_slash = server;
412 if (workstation[0] != '\\' && workstation[1] != '\\') {
413 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
414 } else {
415 workstation_name_slash = workstation;
418 if (!workstation_name_slash || !server_name_slash) {
419 DEBUG(0, ("talloc_asprintf failed!\n"));
420 return NT_STATUS_NO_MEMORY;
423 /* Initialise input parameters */
425 lm.data = lm_response.data;
426 lm.length = lm_response.length;
427 nt.data = nt_response.data;
428 nt.length = nt_response.length;
430 network_info->identity_info.domain_name.string = domain;
431 network_info->identity_info.parameter_control = logon_parameters;
432 network_info->identity_info.logon_id_low = 0xdead;
433 network_info->identity_info.logon_id_high = 0xbeef;
434 network_info->identity_info.account_name.string = username;
435 network_info->identity_info.workstation.string = workstation_name_slash;
437 memcpy(network_info->challenge, chal, 8);
438 network_info->nt = nt;
439 network_info->lm = lm;
441 logon->network = network_info;
443 /* Marshall data and send request */
445 status = dcerpc_netr_LogonSamLogon(b, mem_ctx,
446 server_name_slash,
447 lp_netbios_name(),
448 &clnt_creds,
449 &ret_creds,
450 NetlogonNetworkInformation,
451 logon,
452 validation_level,
453 &validation,
454 &authoritative,
455 &result);
456 if (!NT_STATUS_IS_OK(status)) {
457 return status;
460 /* Always check returned credentials. */
461 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
462 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
463 return NT_STATUS_ACCESS_DENIED;
466 if (!NT_STATUS_IS_OK(result)) {
467 return result;
470 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
472 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
473 if (!NT_STATUS_IS_OK(result)) {
474 return result;
477 return result;
480 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
481 TALLOC_CTX *mem_ctx,
482 uint32 logon_parameters,
483 const char *server,
484 const char *username,
485 const char *domain,
486 const char *workstation,
487 const uint8 chal[8],
488 uint16_t validation_level,
489 DATA_BLOB lm_response,
490 DATA_BLOB nt_response,
491 struct netr_SamInfo3 **info3)
493 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
494 NTSTATUS status;
495 const char *workstation_name_slash;
496 const char *server_name_slash;
497 union netr_LogonLevel *logon = NULL;
498 struct netr_NetworkInfo *network_info;
499 uint8_t authoritative;
500 union netr_Validation validation;
501 struct netr_ChallengeResponse lm;
502 struct netr_ChallengeResponse nt;
503 uint32_t flags = 0;
504 struct dcerpc_binding_handle *b = cli->binding_handle;
506 *info3 = NULL;
508 ZERO_STRUCT(lm);
509 ZERO_STRUCT(nt);
511 logon = talloc_zero(mem_ctx, union netr_LogonLevel);
512 if (!logon) {
513 return NT_STATUS_NO_MEMORY;
516 network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo);
517 if (!network_info) {
518 return NT_STATUS_NO_MEMORY;
521 if (server[0] != '\\' && server[1] != '\\') {
522 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
523 } else {
524 server_name_slash = server;
527 if (workstation[0] != '\\' && workstation[1] != '\\') {
528 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
529 } else {
530 workstation_name_slash = workstation;
533 if (!workstation_name_slash || !server_name_slash) {
534 DEBUG(0, ("talloc_asprintf failed!\n"));
535 return NT_STATUS_NO_MEMORY;
538 /* Initialise input parameters */
540 lm.data = lm_response.data;
541 lm.length = lm_response.length;
542 nt.data = nt_response.data;
543 nt.length = nt_response.length;
545 network_info->identity_info.domain_name.string = domain;
546 network_info->identity_info.parameter_control = logon_parameters;
547 network_info->identity_info.logon_id_low = 0xdead;
548 network_info->identity_info.logon_id_high = 0xbeef;
549 network_info->identity_info.account_name.string = username;
550 network_info->identity_info.workstation.string = workstation_name_slash;
552 memcpy(network_info->challenge, chal, 8);
553 network_info->nt = nt;
554 network_info->lm = lm;
556 logon->network = network_info;
558 /* Marshall data and send request */
560 status = dcerpc_netr_LogonSamLogonEx(b, mem_ctx,
561 server_name_slash,
562 lp_netbios_name(),
563 NetlogonNetworkInformation,
564 logon,
565 validation_level,
566 &validation,
567 &authoritative,
568 &flags,
569 &result);
570 if (!NT_STATUS_IS_OK(status)) {
571 return status;
574 if (!NT_STATUS_IS_OK(result)) {
575 return result;
578 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
580 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
581 if (!NT_STATUS_IS_OK(result)) {
582 return result;
585 return result;
588 /*********************************************************
589 Change the domain password on the PDC.
591 Just changes the password betwen the two values specified.
593 Caller must have the cli connected to the netlogon pipe
594 already.
595 **********************************************************/
597 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
598 TALLOC_CTX *mem_ctx,
599 const char *account_name,
600 const unsigned char orig_trust_passwd_hash[16],
601 const char *new_trust_pwd_cleartext,
602 const unsigned char new_trust_passwd_hash[16],
603 enum netr_SchannelType sec_channel_type)
605 NTSTATUS result, status;
606 struct netr_Authenticator clnt_creds, srv_cred;
607 struct dcerpc_binding_handle *b = cli->binding_handle;
609 if (!cli->dc) {
610 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
611 result = rpccli_netlogon_setup_creds(cli,
612 cli->desthost, /* server name */
613 lp_workgroup(), /* domain */
614 lp_netbios_name(), /* client name */
615 account_name, /* machine account name */
616 orig_trust_passwd_hash,
617 sec_channel_type,
618 &neg_flags);
619 if (!NT_STATUS_IS_OK(result)) {
620 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
621 nt_errstr(result)));
622 return result;
626 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
628 if (cli->dc->negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
630 struct netr_CryptPassword new_password;
631 uint32_t old_timeout;
633 init_netr_CryptPassword(new_trust_pwd_cleartext,
634 cli->dc,
635 &new_password);
637 old_timeout = dcerpc_binding_handle_set_timeout(b, 600000);
639 status = dcerpc_netr_ServerPasswordSet2(b, mem_ctx,
640 cli->srv_name_slash,
641 cli->dc->account_name,
642 sec_channel_type,
643 cli->dc->computer_name,
644 &clnt_creds,
645 &srv_cred,
646 &new_password,
647 &result);
649 dcerpc_binding_handle_set_timeout(b, old_timeout);
651 if (!NT_STATUS_IS_OK(status)) {
652 DEBUG(0,("dcerpc_netr_ServerPasswordSet2 failed: %s\n",
653 nt_errstr(status)));
654 return status;
656 } else {
658 struct samr_Password new_password;
659 uint32_t old_timeout;
661 memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash));
662 netlogon_creds_des_encrypt(cli->dc, &new_password);
664 old_timeout = dcerpc_binding_handle_set_timeout(b, 600000);
666 status = dcerpc_netr_ServerPasswordSet(b, mem_ctx,
667 cli->srv_name_slash,
668 cli->dc->account_name,
669 sec_channel_type,
670 cli->dc->computer_name,
671 &clnt_creds,
672 &srv_cred,
673 &new_password,
674 &result);
676 dcerpc_binding_handle_set_timeout(b, old_timeout);
678 if (!NT_STATUS_IS_OK(status)) {
679 DEBUG(0,("dcerpc_netr_ServerPasswordSet failed: %s\n",
680 nt_errstr(status)));
681 return status;
685 /* Always check returned credentials. */
686 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
687 DEBUG(0,("credentials chain check failed\n"));
688 return NT_STATUS_ACCESS_DENIED;
691 if (!NT_STATUS_IS_OK(result)) {
692 DEBUG(0,("dcerpc_netr_ServerPasswordSet{2} failed: %s\n",
693 nt_errstr(result)));
694 return result;
697 return result;