BUG 9474: Downgrade v4 printer driver requests to v3.
[Samba.git] / source3 / rpc_client / cli_netlogon.c
blob66a50a8f2d97ae9308867310f038c6a7b96e64de
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_validation(cli->dc, validation_level,
471 &validation);
473 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
474 if (!NT_STATUS_IS_OK(result)) {
475 return result;
478 return result;
481 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
482 TALLOC_CTX *mem_ctx,
483 uint32 logon_parameters,
484 const char *server,
485 const char *username,
486 const char *domain,
487 const char *workstation,
488 const uint8 chal[8],
489 uint16_t validation_level,
490 DATA_BLOB lm_response,
491 DATA_BLOB nt_response,
492 struct netr_SamInfo3 **info3)
494 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
495 NTSTATUS status;
496 const char *workstation_name_slash;
497 const char *server_name_slash;
498 union netr_LogonLevel *logon = NULL;
499 struct netr_NetworkInfo *network_info;
500 uint8_t authoritative;
501 union netr_Validation validation;
502 struct netr_ChallengeResponse lm;
503 struct netr_ChallengeResponse nt;
504 uint32_t flags = 0;
505 struct dcerpc_binding_handle *b = cli->binding_handle;
507 *info3 = NULL;
509 ZERO_STRUCT(lm);
510 ZERO_STRUCT(nt);
512 logon = talloc_zero(mem_ctx, union netr_LogonLevel);
513 if (!logon) {
514 return NT_STATUS_NO_MEMORY;
517 network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo);
518 if (!network_info) {
519 return NT_STATUS_NO_MEMORY;
522 if (server[0] != '\\' && server[1] != '\\') {
523 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
524 } else {
525 server_name_slash = server;
528 if (workstation[0] != '\\' && workstation[1] != '\\') {
529 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
530 } else {
531 workstation_name_slash = workstation;
534 if (!workstation_name_slash || !server_name_slash) {
535 DEBUG(0, ("talloc_asprintf failed!\n"));
536 return NT_STATUS_NO_MEMORY;
539 /* Initialise input parameters */
541 lm.data = lm_response.data;
542 lm.length = lm_response.length;
543 nt.data = nt_response.data;
544 nt.length = nt_response.length;
546 network_info->identity_info.domain_name.string = domain;
547 network_info->identity_info.parameter_control = logon_parameters;
548 network_info->identity_info.logon_id_low = 0xdead;
549 network_info->identity_info.logon_id_high = 0xbeef;
550 network_info->identity_info.account_name.string = username;
551 network_info->identity_info.workstation.string = workstation_name_slash;
553 memcpy(network_info->challenge, chal, 8);
554 network_info->nt = nt;
555 network_info->lm = lm;
557 logon->network = network_info;
559 /* Marshall data and send request */
561 status = dcerpc_netr_LogonSamLogonEx(b, mem_ctx,
562 server_name_slash,
563 lp_netbios_name(),
564 NetlogonNetworkInformation,
565 logon,
566 validation_level,
567 &validation,
568 &authoritative,
569 &flags,
570 &result);
571 if (!NT_STATUS_IS_OK(status)) {
572 return status;
575 if (!NT_STATUS_IS_OK(result)) {
576 return result;
579 netlogon_creds_decrypt_samlogon_validation(cli->dc, validation_level,
580 &validation);
582 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
583 if (!NT_STATUS_IS_OK(result)) {
584 return result;
587 return result;
590 /*********************************************************
591 Change the domain password on the PDC.
593 Just changes the password betwen the two values specified.
595 Caller must have the cli connected to the netlogon pipe
596 already.
597 **********************************************************/
599 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
600 TALLOC_CTX *mem_ctx,
601 const char *account_name,
602 const unsigned char orig_trust_passwd_hash[16],
603 const char *new_trust_pwd_cleartext,
604 const unsigned char new_trust_passwd_hash[16],
605 enum netr_SchannelType sec_channel_type)
607 NTSTATUS result, status;
608 struct netr_Authenticator clnt_creds, srv_cred;
609 struct dcerpc_binding_handle *b = cli->binding_handle;
611 if (!cli->dc) {
612 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
613 result = rpccli_netlogon_setup_creds(cli,
614 cli->desthost, /* server name */
615 lp_workgroup(), /* domain */
616 lp_netbios_name(), /* client name */
617 account_name, /* machine account name */
618 orig_trust_passwd_hash,
619 sec_channel_type,
620 &neg_flags);
621 if (!NT_STATUS_IS_OK(result)) {
622 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
623 nt_errstr(result)));
624 return result;
628 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
630 if (cli->dc->negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
632 struct netr_CryptPassword new_password;
633 uint32_t old_timeout;
635 init_netr_CryptPassword(new_trust_pwd_cleartext,
636 cli->dc,
637 &new_password);
639 old_timeout = dcerpc_binding_handle_set_timeout(b, 600000);
641 status = dcerpc_netr_ServerPasswordSet2(b, mem_ctx,
642 cli->srv_name_slash,
643 cli->dc->account_name,
644 sec_channel_type,
645 cli->dc->computer_name,
646 &clnt_creds,
647 &srv_cred,
648 &new_password,
649 &result);
651 dcerpc_binding_handle_set_timeout(b, old_timeout);
653 if (!NT_STATUS_IS_OK(status)) {
654 DEBUG(0,("dcerpc_netr_ServerPasswordSet2 failed: %s\n",
655 nt_errstr(status)));
656 return status;
658 } else {
660 struct samr_Password new_password;
661 uint32_t old_timeout;
663 memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash));
664 netlogon_creds_des_encrypt(cli->dc, &new_password);
666 old_timeout = dcerpc_binding_handle_set_timeout(b, 600000);
668 status = dcerpc_netr_ServerPasswordSet(b, mem_ctx,
669 cli->srv_name_slash,
670 cli->dc->account_name,
671 sec_channel_type,
672 cli->dc->computer_name,
673 &clnt_creds,
674 &srv_cred,
675 &new_password,
676 &result);
678 dcerpc_binding_handle_set_timeout(b, old_timeout);
680 if (!NT_STATUS_IS_OK(status)) {
681 DEBUG(0,("dcerpc_netr_ServerPasswordSet failed: %s\n",
682 nt_errstr(status)));
683 return status;
687 /* Always check returned credentials. */
688 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
689 DEBUG(0,("credentials chain check failed\n"));
690 return NT_STATUS_ACCESS_DENIED;
693 if (!NT_STATUS_IS_OK(result)) {
694 DEBUG(0,("dcerpc_netr_ServerPasswordSet{2} failed: %s\n",
695 nt_errstr(result)));
696 return result;
699 return result;