ctdbd_conn: Remove one call to cluster_fatal
[Samba.git] / source3 / rpc_client / cli_netlogon.c
blob5e8a2fca4122dd60bcf53e6ab77c0f543d394388
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 sec_chan_type,
93 &clnt_chal_send,
94 &srv_chal_recv,
95 &password,
96 &clnt_chal_send,
97 neg_flags);
99 if (!cli->dc) {
100 return NT_STATUS_NO_MEMORY;
104 * Send client auth-2 challenge and receive server repy.
107 status = dcerpc_netr_ServerAuthenticate2(b, talloc_tos(),
108 cli->srv_name_slash,
109 cli->dc->account_name,
110 sec_chan_type,
111 cli->dc->computer_name,
112 &clnt_chal_send, /* input. */
113 &srv_chal_recv, /* output. */
114 &neg_flags,
115 &result);
116 if (!NT_STATUS_IS_OK(status)) {
117 return status;
119 /* we might be talking to NT4, so let's downgrade in that case and retry
120 * with the returned neg_flags - gd */
122 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
123 retried = true;
124 TALLOC_FREE(cli->dc);
125 goto again;
128 if (!NT_STATUS_IS_OK(result)) {
129 return result;
133 * Check the returned value using the initial
134 * server received challenge.
137 if (!netlogon_creds_client_check(cli->dc, &srv_chal_recv)) {
139 * Server replied with bad credential. Fail.
141 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
142 "replied with bad credential\n",
143 cli->desthost ));
144 return NT_STATUS_ACCESS_DENIED;
147 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
148 "chain established.\n",
149 cli->desthost ));
151 cli->dc->negotiate_flags = neg_flags;
152 *neg_flags_inout = neg_flags;
154 return NT_STATUS_OK;
157 /* Logon domain user */
159 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
160 TALLOC_CTX *mem_ctx,
161 uint32 logon_parameters,
162 const char *domain,
163 const char *username,
164 const char *password,
165 const char *workstation,
166 uint16_t validation_level,
167 int logon_type)
169 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
170 NTSTATUS status;
171 struct netr_Authenticator clnt_creds;
172 struct netr_Authenticator ret_creds;
173 union netr_LogonLevel *logon;
174 union netr_Validation validation;
175 uint8_t authoritative;
176 fstring clnt_name_slash;
177 struct dcerpc_binding_handle *b = cli->binding_handle;
179 ZERO_STRUCT(ret_creds);
181 logon = talloc_zero(mem_ctx, union netr_LogonLevel);
182 if (!logon) {
183 return NT_STATUS_NO_MEMORY;
186 if (workstation) {
187 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
188 } else {
189 fstr_sprintf( clnt_name_slash, "\\\\%s", lp_netbios_name() );
192 /* Initialise input parameters */
194 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
196 switch (logon_type) {
197 case NetlogonInteractiveInformation: {
199 struct netr_PasswordInfo *password_info;
201 struct samr_Password lmpassword;
202 struct samr_Password ntpassword;
204 password_info = talloc_zero(mem_ctx, struct netr_PasswordInfo);
205 if (!password_info) {
206 return NT_STATUS_NO_MEMORY;
209 nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash);
211 if (cli->dc->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
212 netlogon_creds_aes_encrypt(cli->dc, lmpassword.hash, 16);
213 netlogon_creds_aes_encrypt(cli->dc, ntpassword.hash, 16);
214 } else if (cli->dc->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
215 netlogon_creds_arcfour_crypt(cli->dc, lmpassword.hash, 16);
216 netlogon_creds_arcfour_crypt(cli->dc, ntpassword.hash, 16);
217 } else {
218 netlogon_creds_des_encrypt(cli->dc, &lmpassword);
219 netlogon_creds_des_encrypt(cli->dc, &ntpassword);
222 password_info->identity_info.domain_name.string = domain;
223 password_info->identity_info.parameter_control = logon_parameters;
224 password_info->identity_info.logon_id_low = 0xdead;
225 password_info->identity_info.logon_id_high = 0xbeef;
226 password_info->identity_info.account_name.string = username;
227 password_info->identity_info.workstation.string = clnt_name_slash;
229 password_info->lmpassword = lmpassword;
230 password_info->ntpassword = ntpassword;
232 logon->password = password_info;
234 break;
236 case NetlogonNetworkInformation: {
237 struct netr_NetworkInfo *network_info;
238 uint8 chal[8];
239 unsigned char local_lm_response[24];
240 unsigned char local_nt_response[24];
241 struct netr_ChallengeResponse lm;
242 struct netr_ChallengeResponse nt;
244 ZERO_STRUCT(lm);
245 ZERO_STRUCT(nt);
247 network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo);
248 if (!network_info) {
249 return NT_STATUS_NO_MEMORY;
252 generate_random_buffer(chal, 8);
254 SMBencrypt(password, chal, local_lm_response);
255 SMBNTencrypt(password, chal, local_nt_response);
257 lm.length = 24;
258 lm.data = local_lm_response;
260 nt.length = 24;
261 nt.data = local_nt_response;
263 network_info->identity_info.domain_name.string = domain;
264 network_info->identity_info.parameter_control = logon_parameters;
265 network_info->identity_info.logon_id_low = 0xdead;
266 network_info->identity_info.logon_id_high = 0xbeef;
267 network_info->identity_info.account_name.string = username;
268 network_info->identity_info.workstation.string = clnt_name_slash;
270 memcpy(network_info->challenge, chal, 8);
271 network_info->nt = nt;
272 network_info->lm = lm;
274 logon->network = network_info;
276 break;
278 default:
279 DEBUG(0, ("switch value %d not supported\n",
280 logon_type));
281 return NT_STATUS_INVALID_INFO_CLASS;
284 status = dcerpc_netr_LogonSamLogon(b, mem_ctx,
285 cli->srv_name_slash,
286 lp_netbios_name(),
287 &clnt_creds,
288 &ret_creds,
289 logon_type,
290 logon,
291 validation_level,
292 &validation,
293 &authoritative,
294 &result);
295 if (!NT_STATUS_IS_OK(status)) {
296 return status;
299 /* Always check returned credentials */
300 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
301 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
302 return NT_STATUS_ACCESS_DENIED;
305 return result;
308 static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
309 uint16_t validation_level,
310 union netr_Validation *validation,
311 struct netr_SamInfo3 **info3_p)
313 struct netr_SamInfo3 *info3;
314 NTSTATUS status;
316 if (validation == NULL) {
317 return NT_STATUS_INVALID_PARAMETER;
320 switch (validation_level) {
321 case 3:
322 if (validation->sam3 == NULL) {
323 return NT_STATUS_INVALID_PARAMETER;
326 info3 = talloc_move(mem_ctx, &validation->sam3);
327 break;
328 case 6:
329 if (validation->sam6 == NULL) {
330 return NT_STATUS_INVALID_PARAMETER;
333 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
334 if (info3 == NULL) {
335 return NT_STATUS_NO_MEMORY;
337 status = copy_netr_SamBaseInfo(info3, &validation->sam6->base, &info3->base);
338 if (!NT_STATUS_IS_OK(status)) {
339 TALLOC_FREE(info3);
340 return status;
343 info3->sidcount = validation->sam6->sidcount;
344 info3->sids = talloc_move(info3, &validation->sam6->sids);
345 break;
346 default:
347 return NT_STATUS_BAD_VALIDATION_CLASS;
350 *info3_p = info3;
352 return NT_STATUS_OK;
356 * Logon domain user with an 'network' SAM logon
358 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
361 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
362 TALLOC_CTX *mem_ctx,
363 uint32 logon_parameters,
364 const char *server,
365 const char *username,
366 const char *domain,
367 const char *workstation,
368 const uint8 chal[8],
369 uint16_t validation_level,
370 DATA_BLOB lm_response,
371 DATA_BLOB nt_response,
372 struct netr_SamInfo3 **info3)
374 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
375 NTSTATUS status;
376 const char *workstation_name_slash;
377 const char *server_name_slash;
378 struct netr_Authenticator clnt_creds;
379 struct netr_Authenticator ret_creds;
380 union netr_LogonLevel *logon = NULL;
381 struct netr_NetworkInfo *network_info;
382 uint8_t authoritative;
383 union netr_Validation validation;
384 struct netr_ChallengeResponse lm;
385 struct netr_ChallengeResponse nt;
386 struct dcerpc_binding_handle *b = cli->binding_handle;
388 *info3 = NULL;
390 ZERO_STRUCT(ret_creds);
392 ZERO_STRUCT(lm);
393 ZERO_STRUCT(nt);
395 logon = talloc_zero(mem_ctx, union netr_LogonLevel);
396 if (!logon) {
397 return NT_STATUS_NO_MEMORY;
400 network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo);
401 if (!network_info) {
402 return NT_STATUS_NO_MEMORY;
405 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
407 if (server[0] != '\\' && server[1] != '\\') {
408 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
409 } else {
410 server_name_slash = server;
413 if (workstation[0] != '\\' && workstation[1] != '\\') {
414 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
415 } else {
416 workstation_name_slash = workstation;
419 if (!workstation_name_slash || !server_name_slash) {
420 DEBUG(0, ("talloc_asprintf failed!\n"));
421 return NT_STATUS_NO_MEMORY;
424 /* Initialise input parameters */
426 lm.data = lm_response.data;
427 lm.length = lm_response.length;
428 nt.data = nt_response.data;
429 nt.length = nt_response.length;
431 network_info->identity_info.domain_name.string = domain;
432 network_info->identity_info.parameter_control = logon_parameters;
433 network_info->identity_info.logon_id_low = 0xdead;
434 network_info->identity_info.logon_id_high = 0xbeef;
435 network_info->identity_info.account_name.string = username;
436 network_info->identity_info.workstation.string = workstation_name_slash;
438 memcpy(network_info->challenge, chal, 8);
439 network_info->nt = nt;
440 network_info->lm = lm;
442 logon->network = network_info;
444 /* Marshall data and send request */
446 status = dcerpc_netr_LogonSamLogon(b, mem_ctx,
447 server_name_slash,
448 lp_netbios_name(),
449 &clnt_creds,
450 &ret_creds,
451 NetlogonNetworkInformation,
452 logon,
453 validation_level,
454 &validation,
455 &authoritative,
456 &result);
457 if (!NT_STATUS_IS_OK(status)) {
458 return status;
461 /* Always check returned credentials. */
462 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
463 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
464 return NT_STATUS_ACCESS_DENIED;
467 if (!NT_STATUS_IS_OK(result)) {
468 return result;
471 netlogon_creds_decrypt_samlogon_validation(cli->dc, validation_level,
472 &validation);
474 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
475 if (!NT_STATUS_IS_OK(result)) {
476 return result;
479 return result;
482 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
483 TALLOC_CTX *mem_ctx,
484 uint32 logon_parameters,
485 const char *server,
486 const char *username,
487 const char *domain,
488 const char *workstation,
489 const uint8 chal[8],
490 uint16_t validation_level,
491 DATA_BLOB lm_response,
492 DATA_BLOB nt_response,
493 struct netr_SamInfo3 **info3)
495 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
496 NTSTATUS status;
497 const char *workstation_name_slash;
498 const char *server_name_slash;
499 union netr_LogonLevel *logon = NULL;
500 struct netr_NetworkInfo *network_info;
501 uint8_t authoritative;
502 union netr_Validation validation;
503 struct netr_ChallengeResponse lm;
504 struct netr_ChallengeResponse nt;
505 uint32_t flags = 0;
506 struct dcerpc_binding_handle *b = cli->binding_handle;
508 *info3 = NULL;
510 ZERO_STRUCT(lm);
511 ZERO_STRUCT(nt);
513 logon = talloc_zero(mem_ctx, union netr_LogonLevel);
514 if (!logon) {
515 return NT_STATUS_NO_MEMORY;
518 network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo);
519 if (!network_info) {
520 return NT_STATUS_NO_MEMORY;
523 if (server[0] != '\\' && server[1] != '\\') {
524 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
525 } else {
526 server_name_slash = server;
529 if (workstation[0] != '\\' && workstation[1] != '\\') {
530 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
531 } else {
532 workstation_name_slash = workstation;
535 if (!workstation_name_slash || !server_name_slash) {
536 DEBUG(0, ("talloc_asprintf failed!\n"));
537 return NT_STATUS_NO_MEMORY;
540 /* Initialise input parameters */
542 lm.data = lm_response.data;
543 lm.length = lm_response.length;
544 nt.data = nt_response.data;
545 nt.length = nt_response.length;
547 network_info->identity_info.domain_name.string = domain;
548 network_info->identity_info.parameter_control = logon_parameters;
549 network_info->identity_info.logon_id_low = 0xdead;
550 network_info->identity_info.logon_id_high = 0xbeef;
551 network_info->identity_info.account_name.string = username;
552 network_info->identity_info.workstation.string = workstation_name_slash;
554 memcpy(network_info->challenge, chal, 8);
555 network_info->nt = nt;
556 network_info->lm = lm;
558 logon->network = network_info;
560 /* Marshall data and send request */
562 status = dcerpc_netr_LogonSamLogonEx(b, mem_ctx,
563 server_name_slash,
564 lp_netbios_name(),
565 NetlogonNetworkInformation,
566 logon,
567 validation_level,
568 &validation,
569 &authoritative,
570 &flags,
571 &result);
572 if (!NT_STATUS_IS_OK(status)) {
573 return status;
576 if (!NT_STATUS_IS_OK(result)) {
577 return result;
580 netlogon_creds_decrypt_samlogon_validation(cli->dc, validation_level,
581 &validation);
583 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
584 if (!NT_STATUS_IS_OK(result)) {
585 return result;
588 return result;
591 /*********************************************************
592 Change the domain password on the PDC.
594 Just changes the password betwen the two values specified.
596 Caller must have the cli connected to the netlogon pipe
597 already.
598 **********************************************************/
600 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
601 TALLOC_CTX *mem_ctx,
602 const char *account_name,
603 const unsigned char orig_trust_passwd_hash[16],
604 const char *new_trust_pwd_cleartext,
605 const unsigned char new_trust_passwd_hash[16],
606 enum netr_SchannelType sec_channel_type)
608 NTSTATUS result, status;
609 struct netr_Authenticator clnt_creds, srv_cred;
610 struct dcerpc_binding_handle *b = cli->binding_handle;
612 if (!cli->dc) {
613 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS |
614 NETLOGON_NEG_SUPPORTS_AES;
615 result = rpccli_netlogon_setup_creds(cli,
616 cli->desthost, /* server name */
617 lp_workgroup(), /* domain */
618 lp_netbios_name(), /* client name */
619 account_name, /* machine account name */
620 orig_trust_passwd_hash,
621 sec_channel_type,
622 &neg_flags);
623 if (!NT_STATUS_IS_OK(result)) {
624 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
625 nt_errstr(result)));
626 return result;
630 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
632 if (cli->dc->negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
634 struct netr_CryptPassword new_password;
635 uint32_t old_timeout;
637 init_netr_CryptPassword(new_trust_pwd_cleartext,
638 cli->dc,
639 &new_password);
641 old_timeout = dcerpc_binding_handle_set_timeout(b, 600000);
643 status = dcerpc_netr_ServerPasswordSet2(b, mem_ctx,
644 cli->srv_name_slash,
645 cli->dc->account_name,
646 sec_channel_type,
647 cli->dc->computer_name,
648 &clnt_creds,
649 &srv_cred,
650 &new_password,
651 &result);
653 dcerpc_binding_handle_set_timeout(b, old_timeout);
655 if (!NT_STATUS_IS_OK(status)) {
656 DEBUG(0,("dcerpc_netr_ServerPasswordSet2 failed: %s\n",
657 nt_errstr(status)));
658 return status;
660 } else {
662 struct samr_Password new_password;
663 uint32_t old_timeout;
665 memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash));
666 netlogon_creds_des_encrypt(cli->dc, &new_password);
668 old_timeout = dcerpc_binding_handle_set_timeout(b, 600000);
670 status = dcerpc_netr_ServerPasswordSet(b, mem_ctx,
671 cli->srv_name_slash,
672 cli->dc->account_name,
673 sec_channel_type,
674 cli->dc->computer_name,
675 &clnt_creds,
676 &srv_cred,
677 &new_password,
678 &result);
680 dcerpc_binding_handle_set_timeout(b, old_timeout);
682 if (!NT_STATUS_IS_OK(status)) {
683 DEBUG(0,("dcerpc_netr_ServerPasswordSet failed: %s\n",
684 nt_errstr(status)));
685 return status;
689 /* Always check returned credentials. */
690 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
691 DEBUG(0,("credentials chain check failed\n"));
692 return NT_STATUS_ACCESS_DENIED;
695 if (!NT_STATUS_IS_OK(result)) {
696 DEBUG(0,("dcerpc_netr_ServerPasswordSet{2} failed: %s\n",
697 nt_errstr(result)));
698 return result;
701 return result;