librpc/rpc: move dcerpc_binding_handle stuff to rpc_common.h
[Samba/gebeck_regimport.git] / source3 / rpc_client / cli_netlogon.c
blob8dc232f412679cf113befcb94a1914167f784e06
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 "../libcli/auth/libcli_auth.h"
25 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
26 #include "rpc_client/cli_netlogon.h"
27 #include "rpc_client/init_netlogon.h"
28 #include "rpc_client/util_netlogon.h"
29 #include "../libcli/security/security.h"
31 /****************************************************************************
32 Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
33 credentials chain. Stores the credentials in the struct dcinfo in the
34 netlogon pipe struct.
35 ****************************************************************************/
37 NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
38 const char *server_name,
39 const char *domain,
40 const char *clnt_name,
41 const char *machine_account,
42 const unsigned char machine_pwd[16],
43 enum netr_SchannelType sec_chan_type,
44 uint32_t *neg_flags_inout)
46 NTSTATUS status;
47 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
48 struct netr_Credential clnt_chal_send;
49 struct netr_Credential srv_chal_recv;
50 struct samr_Password password;
51 bool retried = false;
52 fstring mach_acct;
53 uint32_t neg_flags = *neg_flags_inout;
54 struct dcerpc_binding_handle *b = cli->binding_handle;
56 if (!ndr_syntax_id_equal(&cli->abstract_syntax,
57 &ndr_table_netlogon.syntax_id)) {
58 return NT_STATUS_INVALID_PARAMETER;
61 TALLOC_FREE(cli->dc);
63 /* Store the machine account password we're going to use. */
64 memcpy(password.hash, machine_pwd, 16);
66 fstr_sprintf( mach_acct, "%s$", machine_account);
68 again:
69 /* Create the client challenge. */
70 generate_random_buffer(clnt_chal_send.data, 8);
72 /* Get the server challenge. */
73 status = dcerpc_netr_ServerReqChallenge(b, talloc_tos(),
74 cli->srv_name_slash,
75 clnt_name,
76 &clnt_chal_send,
77 &srv_chal_recv,
78 &result);
79 if (!NT_STATUS_IS_OK(status)) {
80 return status;
82 if (!NT_STATUS_IS_OK(result)) {
83 return result;
86 /* Calculate the session key and client credentials */
88 cli->dc = netlogon_creds_client_init(cli,
89 mach_acct,
90 clnt_name,
91 &clnt_chal_send,
92 &srv_chal_recv,
93 &password,
94 &clnt_chal_send,
95 neg_flags);
97 if (!cli->dc) {
98 return NT_STATUS_NO_MEMORY;
102 * Send client auth-2 challenge and receive server repy.
105 status = dcerpc_netr_ServerAuthenticate2(b, talloc_tos(),
106 cli->srv_name_slash,
107 cli->dc->account_name,
108 sec_chan_type,
109 cli->dc->computer_name,
110 &clnt_chal_send, /* input. */
111 &srv_chal_recv, /* output. */
112 &neg_flags,
113 &result);
114 if (!NT_STATUS_IS_OK(status)) {
115 return status;
117 /* we might be talking to NT4, so let's downgrade in that case and retry
118 * with the returned neg_flags - gd */
120 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
121 retried = true;
122 TALLOC_FREE(cli->dc);
123 goto again;
126 if (!NT_STATUS_IS_OK(result)) {
127 return result;
131 * Check the returned value using the initial
132 * server received challenge.
135 if (!netlogon_creds_client_check(cli->dc, &srv_chal_recv)) {
137 * Server replied with bad credential. Fail.
139 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
140 "replied with bad credential\n",
141 cli->desthost ));
142 return NT_STATUS_ACCESS_DENIED;
145 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
146 "chain established.\n",
147 cli->desthost ));
149 cli->dc->negotiate_flags = neg_flags;
150 *neg_flags_inout = neg_flags;
152 return NT_STATUS_OK;
155 /* Logon domain user */
157 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
158 TALLOC_CTX *mem_ctx,
159 uint32 logon_parameters,
160 const char *domain,
161 const char *username,
162 const char *password,
163 const char *workstation,
164 uint16_t validation_level,
165 int logon_type)
167 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
168 NTSTATUS status;
169 struct netr_Authenticator clnt_creds;
170 struct netr_Authenticator ret_creds;
171 union netr_LogonLevel *logon;
172 union netr_Validation validation;
173 uint8_t authoritative;
174 fstring clnt_name_slash;
175 struct dcerpc_binding_handle *b = cli->binding_handle;
177 ZERO_STRUCT(ret_creds);
179 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
180 if (!logon) {
181 return NT_STATUS_NO_MEMORY;
184 if (workstation) {
185 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
186 } else {
187 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
190 /* Initialise input parameters */
192 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
194 switch (logon_type) {
195 case NetlogonInteractiveInformation: {
197 struct netr_PasswordInfo *password_info;
199 struct samr_Password lmpassword;
200 struct samr_Password ntpassword;
202 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
203 if (!password_info) {
204 return NT_STATUS_NO_MEMORY;
207 nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash);
209 if (cli->dc->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
210 netlogon_creds_arcfour_crypt(cli->dc, lmpassword.hash, 16);
211 netlogon_creds_arcfour_crypt(cli->dc, ntpassword.hash, 16);
212 } else {
213 netlogon_creds_des_encrypt(cli->dc, &lmpassword);
214 netlogon_creds_des_encrypt(cli->dc, &ntpassword);
217 password_info->identity_info.domain_name.string = domain;
218 password_info->identity_info.parameter_control = logon_parameters;
219 password_info->identity_info.logon_id_low = 0xdead;
220 password_info->identity_info.logon_id_high = 0xbeef;
221 password_info->identity_info.account_name.string = username;
222 password_info->identity_info.workstation.string = clnt_name_slash;
224 password_info->lmpassword = lmpassword;
225 password_info->ntpassword = ntpassword;
227 logon->password = password_info;
229 break;
231 case NetlogonNetworkInformation: {
232 struct netr_NetworkInfo *network_info;
233 uint8 chal[8];
234 unsigned char local_lm_response[24];
235 unsigned char local_nt_response[24];
236 struct netr_ChallengeResponse lm;
237 struct netr_ChallengeResponse nt;
239 ZERO_STRUCT(lm);
240 ZERO_STRUCT(nt);
242 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
243 if (!network_info) {
244 return NT_STATUS_NO_MEMORY;
247 generate_random_buffer(chal, 8);
249 SMBencrypt(password, chal, local_lm_response);
250 SMBNTencrypt(password, chal, local_nt_response);
252 lm.length = 24;
253 lm.data = local_lm_response;
255 nt.length = 24;
256 nt.data = local_nt_response;
258 network_info->identity_info.domain_name.string = domain;
259 network_info->identity_info.parameter_control = logon_parameters;
260 network_info->identity_info.logon_id_low = 0xdead;
261 network_info->identity_info.logon_id_high = 0xbeef;
262 network_info->identity_info.account_name.string = username;
263 network_info->identity_info.workstation.string = clnt_name_slash;
265 memcpy(network_info->challenge, chal, 8);
266 network_info->nt = nt;
267 network_info->lm = lm;
269 logon->network = network_info;
271 break;
273 default:
274 DEBUG(0, ("switch value %d not supported\n",
275 logon_type));
276 return NT_STATUS_INVALID_INFO_CLASS;
279 status = dcerpc_netr_LogonSamLogon(b, mem_ctx,
280 cli->srv_name_slash,
281 global_myname(),
282 &clnt_creds,
283 &ret_creds,
284 logon_type,
285 logon,
286 validation_level,
287 &validation,
288 &authoritative,
289 &result);
290 if (!NT_STATUS_IS_OK(status)) {
291 return status;
294 /* Always check returned credentials */
295 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
296 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
297 return NT_STATUS_ACCESS_DENIED;
300 return result;
303 static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
304 uint16_t validation_level,
305 union netr_Validation *validation,
306 struct netr_SamInfo3 **info3_p)
308 struct netr_SamInfo3 *info3;
309 NTSTATUS status;
311 if (validation == NULL) {
312 return NT_STATUS_INVALID_PARAMETER;
315 switch (validation_level) {
316 case 3:
317 if (validation->sam3 == NULL) {
318 return NT_STATUS_INVALID_PARAMETER;
321 info3 = talloc_move(mem_ctx, &validation->sam3);
322 break;
323 case 6:
324 if (validation->sam6 == NULL) {
325 return NT_STATUS_INVALID_PARAMETER;
328 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
329 if (info3 == NULL) {
330 return NT_STATUS_NO_MEMORY;
332 status = copy_netr_SamBaseInfo(info3, &validation->sam6->base, &info3->base);
333 if (!NT_STATUS_IS_OK(status)) {
334 TALLOC_FREE(info3);
335 return status;
338 info3->sidcount = validation->sam6->sidcount;
339 info3->sids = talloc_move(info3, &validation->sam6->sids);
340 break;
341 default:
342 return NT_STATUS_BAD_VALIDATION_CLASS;
345 *info3_p = info3;
347 return NT_STATUS_OK;
351 * Logon domain user with an 'network' SAM logon
353 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
356 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
357 TALLOC_CTX *mem_ctx,
358 uint32 logon_parameters,
359 const char *server,
360 const char *username,
361 const char *domain,
362 const char *workstation,
363 const uint8 chal[8],
364 uint16_t validation_level,
365 DATA_BLOB lm_response,
366 DATA_BLOB nt_response,
367 struct netr_SamInfo3 **info3)
369 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
370 NTSTATUS status;
371 const char *workstation_name_slash;
372 const char *server_name_slash;
373 struct netr_Authenticator clnt_creds;
374 struct netr_Authenticator ret_creds;
375 union netr_LogonLevel *logon = NULL;
376 struct netr_NetworkInfo *network_info;
377 uint8_t authoritative;
378 union netr_Validation validation;
379 struct netr_ChallengeResponse lm;
380 struct netr_ChallengeResponse nt;
381 struct dcerpc_binding_handle *b = cli->binding_handle;
383 *info3 = NULL;
385 ZERO_STRUCT(ret_creds);
387 ZERO_STRUCT(lm);
388 ZERO_STRUCT(nt);
390 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
391 if (!logon) {
392 return NT_STATUS_NO_MEMORY;
395 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
396 if (!network_info) {
397 return NT_STATUS_NO_MEMORY;
400 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
402 if (server[0] != '\\' && server[1] != '\\') {
403 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
404 } else {
405 server_name_slash = server;
408 if (workstation[0] != '\\' && workstation[1] != '\\') {
409 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
410 } else {
411 workstation_name_slash = workstation;
414 if (!workstation_name_slash || !server_name_slash) {
415 DEBUG(0, ("talloc_asprintf failed!\n"));
416 return NT_STATUS_NO_MEMORY;
419 /* Initialise input parameters */
421 lm.data = lm_response.data;
422 lm.length = lm_response.length;
423 nt.data = nt_response.data;
424 nt.length = nt_response.length;
426 network_info->identity_info.domain_name.string = domain;
427 network_info->identity_info.parameter_control = logon_parameters;
428 network_info->identity_info.logon_id_low = 0xdead;
429 network_info->identity_info.logon_id_high = 0xbeef;
430 network_info->identity_info.account_name.string = username;
431 network_info->identity_info.workstation.string = workstation_name_slash;
433 memcpy(network_info->challenge, chal, 8);
434 network_info->nt = nt;
435 network_info->lm = lm;
437 logon->network = network_info;
439 /* Marshall data and send request */
441 status = dcerpc_netr_LogonSamLogon(b, mem_ctx,
442 server_name_slash,
443 global_myname(),
444 &clnt_creds,
445 &ret_creds,
446 NetlogonNetworkInformation,
447 logon,
448 validation_level,
449 &validation,
450 &authoritative,
451 &result);
452 if (!NT_STATUS_IS_OK(status)) {
453 return status;
456 /* Always check returned credentials. */
457 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
458 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
459 return NT_STATUS_ACCESS_DENIED;
462 if (!NT_STATUS_IS_OK(result)) {
463 return result;
466 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
468 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
469 if (!NT_STATUS_IS_OK(result)) {
470 return result;
473 return result;
476 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
477 TALLOC_CTX *mem_ctx,
478 uint32 logon_parameters,
479 const char *server,
480 const char *username,
481 const char *domain,
482 const char *workstation,
483 const uint8 chal[8],
484 uint16_t validation_level,
485 DATA_BLOB lm_response,
486 DATA_BLOB nt_response,
487 struct netr_SamInfo3 **info3)
489 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
490 NTSTATUS status;
491 const char *workstation_name_slash;
492 const char *server_name_slash;
493 union netr_LogonLevel *logon = NULL;
494 struct netr_NetworkInfo *network_info;
495 uint8_t authoritative;
496 union netr_Validation validation;
497 struct netr_ChallengeResponse lm;
498 struct netr_ChallengeResponse nt;
499 uint32_t flags = 0;
500 struct dcerpc_binding_handle *b = cli->binding_handle;
502 *info3 = NULL;
504 ZERO_STRUCT(lm);
505 ZERO_STRUCT(nt);
507 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
508 if (!logon) {
509 return NT_STATUS_NO_MEMORY;
512 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
513 if (!network_info) {
514 return NT_STATUS_NO_MEMORY;
517 if (server[0] != '\\' && server[1] != '\\') {
518 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
519 } else {
520 server_name_slash = server;
523 if (workstation[0] != '\\' && workstation[1] != '\\') {
524 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
525 } else {
526 workstation_name_slash = workstation;
529 if (!workstation_name_slash || !server_name_slash) {
530 DEBUG(0, ("talloc_asprintf failed!\n"));
531 return NT_STATUS_NO_MEMORY;
534 /* Initialise input parameters */
536 lm.data = lm_response.data;
537 lm.length = lm_response.length;
538 nt.data = nt_response.data;
539 nt.length = nt_response.length;
541 network_info->identity_info.domain_name.string = domain;
542 network_info->identity_info.parameter_control = logon_parameters;
543 network_info->identity_info.logon_id_low = 0xdead;
544 network_info->identity_info.logon_id_high = 0xbeef;
545 network_info->identity_info.account_name.string = username;
546 network_info->identity_info.workstation.string = workstation_name_slash;
548 memcpy(network_info->challenge, chal, 8);
549 network_info->nt = nt;
550 network_info->lm = lm;
552 logon->network = network_info;
554 /* Marshall data and send request */
556 status = dcerpc_netr_LogonSamLogonEx(b, mem_ctx,
557 server_name_slash,
558 global_myname(),
559 NetlogonNetworkInformation,
560 logon,
561 validation_level,
562 &validation,
563 &authoritative,
564 &flags,
565 &result);
566 if (!NT_STATUS_IS_OK(status)) {
567 return status;
570 if (!NT_STATUS_IS_OK(result)) {
571 return result;
574 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
576 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
577 if (!NT_STATUS_IS_OK(result)) {
578 return result;
581 return result;
584 /*********************************************************
585 Change the domain password on the PDC.
587 Just changes the password betwen the two values specified.
589 Caller must have the cli connected to the netlogon pipe
590 already.
591 **********************************************************/
593 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
594 TALLOC_CTX *mem_ctx,
595 const char *account_name,
596 const unsigned char orig_trust_passwd_hash[16],
597 const char *new_trust_pwd_cleartext,
598 const unsigned char new_trust_passwd_hash[16],
599 enum netr_SchannelType sec_channel_type)
601 NTSTATUS result, status;
602 struct netr_Authenticator clnt_creds, srv_cred;
603 struct dcerpc_binding_handle *b = cli->binding_handle;
605 if (!cli->dc) {
606 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
607 result = rpccli_netlogon_setup_creds(cli,
608 cli->desthost, /* server name */
609 lp_workgroup(), /* domain */
610 global_myname(), /* client name */
611 account_name, /* machine account name */
612 orig_trust_passwd_hash,
613 sec_channel_type,
614 &neg_flags);
615 if (!NT_STATUS_IS_OK(result)) {
616 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
617 nt_errstr(result)));
618 return result;
622 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
624 if (cli->dc->negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
626 struct netr_CryptPassword new_password;
628 init_netr_CryptPassword(new_trust_pwd_cleartext,
629 cli->dc->session_key,
630 &new_password);
632 status = dcerpc_netr_ServerPasswordSet2(b, mem_ctx,
633 cli->srv_name_slash,
634 cli->dc->account_name,
635 sec_channel_type,
636 cli->dc->computer_name,
637 &clnt_creds,
638 &srv_cred,
639 &new_password,
640 &result);
641 if (!NT_STATUS_IS_OK(status)) {
642 DEBUG(0,("dcerpc_netr_ServerPasswordSet2 failed: %s\n",
643 nt_errstr(status)));
644 return status;
646 } else {
648 struct samr_Password new_password;
649 memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash));
650 netlogon_creds_des_encrypt(cli->dc, &new_password);
652 status = dcerpc_netr_ServerPasswordSet(b, mem_ctx,
653 cli->srv_name_slash,
654 cli->dc->account_name,
655 sec_channel_type,
656 cli->dc->computer_name,
657 &clnt_creds,
658 &srv_cred,
659 &new_password,
660 &result);
661 if (!NT_STATUS_IS_OK(status)) {
662 DEBUG(0,("dcerpc_netr_ServerPasswordSet failed: %s\n",
663 nt_errstr(status)));
664 return status;
668 /* Always check returned credentials. */
669 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
670 DEBUG(0,("credentials chain check failed\n"));
671 return NT_STATUS_ACCESS_DENIED;
674 if (!NT_STATUS_IS_OK(result)) {
675 DEBUG(0,("dcerpc_netr_ServerPasswordSet{2} failed: %s\n",
676 nt_errstr(result)));
677 return result;
680 return result;