s3: Fix bug #9085.
[Samba.git] / source3 / rpc_client / cli_netlogon.c
blobca66faa3c3d9ea1aff1ca1f5f14f85beb6c41168
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/cli_netlogon.h"
27 /****************************************************************************
28 Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
29 credentials chain. Stores the credentials in the struct dcinfo in the
30 netlogon pipe struct.
31 ****************************************************************************/
33 NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
34 const char *server_name,
35 const char *domain,
36 const char *clnt_name,
37 const char *machine_account,
38 const unsigned char machine_pwd[16],
39 enum netr_SchannelType sec_chan_type,
40 uint32_t *neg_flags_inout)
42 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
43 struct netr_Credential clnt_chal_send;
44 struct netr_Credential srv_chal_recv;
45 struct samr_Password password;
46 bool retried = false;
47 fstring mach_acct;
48 uint32_t neg_flags = *neg_flags_inout;
50 if (!ndr_syntax_id_equal(&cli->abstract_syntax,
51 &ndr_table_netlogon.syntax_id)) {
52 return NT_STATUS_INVALID_PARAMETER;
55 TALLOC_FREE(cli->dc);
57 /* Store the machine account password we're going to use. */
58 memcpy(password.hash, machine_pwd, 16);
60 fstr_sprintf( mach_acct, "%s$", machine_account);
62 again:
63 /* Create the client challenge. */
64 generate_random_buffer(clnt_chal_send.data, 8);
66 /* Get the server challenge. */
67 result = rpccli_netr_ServerReqChallenge(cli, talloc_tos(),
68 cli->srv_name_slash,
69 clnt_name,
70 &clnt_chal_send,
71 &srv_chal_recv);
72 if (!NT_STATUS_IS_OK(result)) {
73 return result;
76 /* Calculate the session key and client credentials */
78 cli->dc = netlogon_creds_client_init(cli,
79 mach_acct,
80 clnt_name,
81 &clnt_chal_send,
82 &srv_chal_recv,
83 &password,
84 &clnt_chal_send,
85 neg_flags);
87 if (!cli->dc) {
88 return NT_STATUS_NO_MEMORY;
92 * Send client auth-2 challenge and receive server repy.
95 result = rpccli_netr_ServerAuthenticate2(cli, talloc_tos(),
96 cli->srv_name_slash,
97 cli->dc->account_name,
98 sec_chan_type,
99 cli->dc->computer_name,
100 &clnt_chal_send, /* input. */
101 &srv_chal_recv, /* output. */
102 &neg_flags);
104 /* we might be talking to NT4, so let's downgrade in that case and retry
105 * with the returned neg_flags - gd */
107 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
108 retried = true;
109 TALLOC_FREE(cli->dc);
110 goto again;
113 if (!NT_STATUS_IS_OK(result)) {
114 return result;
118 * Check the returned value using the initial
119 * server received challenge.
122 if (!netlogon_creds_client_check(cli->dc, &srv_chal_recv)) {
124 * Server replied with bad credential. Fail.
126 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
127 "replied with bad credential\n",
128 cli->desthost ));
129 return NT_STATUS_ACCESS_DENIED;
132 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
133 "chain established.\n",
134 cli->desthost ));
136 cli->dc->negotiate_flags = neg_flags;
137 *neg_flags_inout = neg_flags;
139 return NT_STATUS_OK;
142 /* Logon domain user */
144 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
145 TALLOC_CTX *mem_ctx,
146 uint32 logon_parameters,
147 const char *domain,
148 const char *username,
149 const char *password,
150 const char *workstation,
151 int logon_type)
153 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
154 struct netr_Authenticator clnt_creds;
155 struct netr_Authenticator ret_creds;
156 union netr_LogonLevel *logon;
157 union netr_Validation validation;
158 uint8_t authoritative;
159 int validation_level = 3;
160 fstring clnt_name_slash;
161 uint8 zeros[16];
163 ZERO_STRUCT(ret_creds);
164 ZERO_STRUCT(zeros);
166 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
167 if (!logon) {
168 return NT_STATUS_NO_MEMORY;
171 if (workstation) {
172 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
173 } else {
174 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
177 /* Initialise input parameters */
179 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
181 switch (logon_type) {
182 case NetlogonInteractiveInformation: {
184 struct netr_PasswordInfo *password_info;
186 struct samr_Password lmpassword;
187 struct samr_Password ntpassword;
189 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
190 if (!password_info) {
191 return NT_STATUS_NO_MEMORY;
194 nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash);
196 if (cli->dc->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
197 netlogon_creds_arcfour_crypt(cli->dc, lmpassword.hash, 16);
198 netlogon_creds_arcfour_crypt(cli->dc, ntpassword.hash, 16);
199 } else {
200 netlogon_creds_des_encrypt(cli->dc, &lmpassword);
201 netlogon_creds_des_encrypt(cli->dc, &ntpassword);
204 password_info->identity_info.domain_name.string = domain;
205 password_info->identity_info.parameter_control = logon_parameters;
206 password_info->identity_info.logon_id_low = 0xdead;
207 password_info->identity_info.logon_id_high = 0xbeef;
208 password_info->identity_info.account_name.string = username;
209 password_info->identity_info.workstation.string = clnt_name_slash;
211 password_info->lmpassword = lmpassword;
212 password_info->ntpassword = ntpassword;
214 logon->password = password_info;
216 break;
218 case NetlogonNetworkInformation: {
219 struct netr_NetworkInfo *network_info;
220 uint8 chal[8];
221 unsigned char local_lm_response[24];
222 unsigned char local_nt_response[24];
223 struct netr_ChallengeResponse lm;
224 struct netr_ChallengeResponse nt;
226 ZERO_STRUCT(lm);
227 ZERO_STRUCT(nt);
229 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
230 if (!network_info) {
231 return NT_STATUS_NO_MEMORY;
234 generate_random_buffer(chal, 8);
236 SMBencrypt(password, chal, local_lm_response);
237 SMBNTencrypt(password, chal, local_nt_response);
239 lm.length = 24;
240 lm.data = local_lm_response;
242 nt.length = 24;
243 nt.data = local_nt_response;
245 network_info->identity_info.domain_name.string = domain;
246 network_info->identity_info.parameter_control = logon_parameters;
247 network_info->identity_info.logon_id_low = 0xdead;
248 network_info->identity_info.logon_id_high = 0xbeef;
249 network_info->identity_info.account_name.string = username;
250 network_info->identity_info.workstation.string = clnt_name_slash;
252 memcpy(network_info->challenge, chal, 8);
253 network_info->nt = nt;
254 network_info->lm = lm;
256 logon->network = network_info;
258 break;
260 default:
261 DEBUG(0, ("switch value %d not supported\n",
262 logon_type));
263 return NT_STATUS_INVALID_INFO_CLASS;
266 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
267 cli->srv_name_slash,
268 global_myname(),
269 &clnt_creds,
270 &ret_creds,
271 logon_type,
272 logon,
273 validation_level,
274 &validation,
275 &authoritative);
277 /* Always check returned credentials */
278 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
279 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
280 return NT_STATUS_ACCESS_DENIED;
283 return result;
286 #define COPY_LSA_STRING(mem_ctx, in, out, name) do { \
287 if (in->name.string) { \
288 out->name.string = talloc_strdup(mem_ctx, in->name.string); \
289 NT_STATUS_HAVE_NO_MEMORY(out->name.string); \
291 } while (0)
293 static NTSTATUS copy_netr_SamBaseInfo(TALLOC_CTX *mem_ctx,
294 const struct netr_SamBaseInfo *in,
295 struct netr_SamBaseInfo *out)
297 /* first copy all, then realloc pointers */
298 *out = *in;
300 COPY_LSA_STRING(mem_ctx, in, out, account_name);
301 COPY_LSA_STRING(mem_ctx, in, out, full_name);
302 COPY_LSA_STRING(mem_ctx, in, out, logon_script);
303 COPY_LSA_STRING(mem_ctx, in, out, profile_path);
304 COPY_LSA_STRING(mem_ctx, in, out, home_directory);
305 COPY_LSA_STRING(mem_ctx, in, out, home_drive);
307 if (in->groups.count) {
308 out->groups.rids = (struct samr_RidWithAttribute *)
309 talloc_memdup(mem_ctx, in->groups.rids,
310 (sizeof(struct samr_RidWithAttribute) *
311 in->groups.count));
312 NT_STATUS_HAVE_NO_MEMORY(out->groups.rids);
315 COPY_LSA_STRING(mem_ctx, in, out, logon_server);
316 COPY_LSA_STRING(mem_ctx, in, out, domain);
318 if (in->domain_sid) {
319 out->domain_sid = sid_dup_talloc(mem_ctx, in->domain_sid);
320 NT_STATUS_HAVE_NO_MEMORY(out->domain_sid);
323 return NT_STATUS_OK;
326 static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
327 uint16_t validation_level,
328 union netr_Validation *validation,
329 struct netr_SamInfo3 **info3_p)
331 struct netr_SamInfo3 *info3;
332 NTSTATUS status;
334 if (validation == NULL) {
335 return NT_STATUS_INVALID_PARAMETER;
338 switch (validation_level) {
339 case 3:
340 if (validation->sam3 == NULL) {
341 return NT_STATUS_INVALID_PARAMETER;
344 info3 = talloc_move(mem_ctx, &validation->sam3);
345 break;
346 case 6:
347 if (validation->sam6 == NULL) {
348 return NT_STATUS_INVALID_PARAMETER;
351 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
352 if (info3 == NULL) {
353 return NT_STATUS_NO_MEMORY;
355 status = copy_netr_SamBaseInfo(info3, &validation->sam6->base, &info3->base);
356 if (!NT_STATUS_IS_OK(status)) {
357 TALLOC_FREE(info3);
358 return status;
361 info3->sidcount = validation->sam6->sidcount;
362 info3->sids = talloc_move(info3, &validation->sam6->sids);
363 break;
364 default:
365 return NT_STATUS_BAD_VALIDATION_CLASS;
368 *info3_p = info3;
370 return NT_STATUS_OK;
374 * Logon domain user with an 'network' SAM logon
376 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
379 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
380 TALLOC_CTX *mem_ctx,
381 uint32 logon_parameters,
382 const char *server,
383 const char *username,
384 const char *domain,
385 const char *workstation,
386 const uint8 chal[8],
387 uint16_t validation_level,
388 DATA_BLOB lm_response,
389 DATA_BLOB nt_response,
390 struct netr_SamInfo3 **info3)
392 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
393 const char *workstation_name_slash;
394 const char *server_name_slash;
395 uint8 zeros[16];
396 struct netr_Authenticator clnt_creds;
397 struct netr_Authenticator ret_creds;
398 union netr_LogonLevel *logon = NULL;
399 struct netr_NetworkInfo *network_info;
400 uint8_t authoritative;
401 union netr_Validation validation;
402 struct netr_ChallengeResponse lm;
403 struct netr_ChallengeResponse nt;
405 *info3 = NULL;
407 ZERO_STRUCT(zeros);
408 ZERO_STRUCT(ret_creds);
410 ZERO_STRUCT(lm);
411 ZERO_STRUCT(nt);
413 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
414 if (!logon) {
415 return NT_STATUS_NO_MEMORY;
418 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
419 if (!network_info) {
420 return NT_STATUS_NO_MEMORY;
423 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
425 if (server[0] != '\\' && server[1] != '\\') {
426 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
427 } else {
428 server_name_slash = server;
431 if (workstation[0] != '\\' && workstation[1] != '\\') {
432 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
433 } else {
434 workstation_name_slash = workstation;
437 if (!workstation_name_slash || !server_name_slash) {
438 DEBUG(0, ("talloc_asprintf failed!\n"));
439 return NT_STATUS_NO_MEMORY;
442 /* Initialise input parameters */
444 lm.data = lm_response.data;
445 lm.length = lm_response.length;
446 nt.data = nt_response.data;
447 nt.length = nt_response.length;
449 network_info->identity_info.domain_name.string = domain;
450 network_info->identity_info.parameter_control = logon_parameters;
451 network_info->identity_info.logon_id_low = 0xdead;
452 network_info->identity_info.logon_id_high = 0xbeef;
453 network_info->identity_info.account_name.string = username;
454 network_info->identity_info.workstation.string = workstation_name_slash;
456 memcpy(network_info->challenge, chal, 8);
457 network_info->nt = nt;
458 network_info->lm = lm;
460 logon->network = network_info;
462 /* Marshall data and send request */
464 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
465 server_name_slash,
466 global_myname(),
467 &clnt_creds,
468 &ret_creds,
469 NetlogonNetworkInformation,
470 logon,
471 validation_level,
472 &validation,
473 &authoritative);
474 if (!NT_STATUS_IS_OK(result)) {
475 return result;
478 /* Always check returned credentials. */
479 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
480 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
481 return NT_STATUS_ACCESS_DENIED;
484 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
486 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
487 if (!NT_STATUS_IS_OK(result)) {
488 return result;
491 return result;
494 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
495 TALLOC_CTX *mem_ctx,
496 uint32 logon_parameters,
497 const char *server,
498 const char *username,
499 const char *domain,
500 const char *workstation,
501 const uint8 chal[8],
502 uint16_t validation_level,
503 DATA_BLOB lm_response,
504 DATA_BLOB nt_response,
505 struct netr_SamInfo3 **info3)
507 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
508 const char *workstation_name_slash;
509 const char *server_name_slash;
510 uint8 zeros[16];
511 union netr_LogonLevel *logon = NULL;
512 struct netr_NetworkInfo *network_info;
513 uint8_t authoritative;
514 union netr_Validation validation;
515 struct netr_ChallengeResponse lm;
516 struct netr_ChallengeResponse nt;
517 uint32_t flags = 0;
519 *info3 = NULL;
521 ZERO_STRUCT(zeros);
523 ZERO_STRUCT(lm);
524 ZERO_STRUCT(nt);
526 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
527 if (!logon) {
528 return NT_STATUS_NO_MEMORY;
531 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
532 if (!network_info) {
533 return NT_STATUS_NO_MEMORY;
536 if (server[0] != '\\' && server[1] != '\\') {
537 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
538 } else {
539 server_name_slash = server;
542 if (workstation[0] != '\\' && workstation[1] != '\\') {
543 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
544 } else {
545 workstation_name_slash = workstation;
548 if (!workstation_name_slash || !server_name_slash) {
549 DEBUG(0, ("talloc_asprintf failed!\n"));
550 return NT_STATUS_NO_MEMORY;
553 /* Initialise input parameters */
555 lm.data = lm_response.data;
556 lm.length = lm_response.length;
557 nt.data = nt_response.data;
558 nt.length = nt_response.length;
560 network_info->identity_info.domain_name.string = domain;
561 network_info->identity_info.parameter_control = logon_parameters;
562 network_info->identity_info.logon_id_low = 0xdead;
563 network_info->identity_info.logon_id_high = 0xbeef;
564 network_info->identity_info.account_name.string = username;
565 network_info->identity_info.workstation.string = workstation_name_slash;
567 memcpy(network_info->challenge, chal, 8);
568 network_info->nt = nt;
569 network_info->lm = lm;
571 logon->network = network_info;
573 /* Marshall data and send request */
575 result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
576 server_name_slash,
577 global_myname(),
578 NetlogonNetworkInformation,
579 logon,
580 validation_level,
581 &validation,
582 &authoritative,
583 &flags);
584 if (!NT_STATUS_IS_OK(result)) {
585 return result;
588 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
590 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
591 if (!NT_STATUS_IS_OK(result)) {
592 return result;
595 return result;
598 /*********************************************************
599 Change the domain password on the PDC.
601 Just changes the password betwen the two values specified.
603 Caller must have the cli connected to the netlogon pipe
604 already.
605 **********************************************************/
607 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
608 TALLOC_CTX *mem_ctx,
609 const char *account_name,
610 const unsigned char orig_trust_passwd_hash[16],
611 const char *new_trust_pwd_cleartext,
612 const unsigned char new_trust_passwd_hash[16],
613 enum netr_SchannelType sec_channel_type)
615 NTSTATUS result;
616 struct netr_Authenticator clnt_creds, srv_cred;
618 if (!cli->dc) {
619 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
620 result = rpccli_netlogon_setup_creds(cli,
621 cli->desthost, /* server name */
622 lp_workgroup(), /* domain */
623 global_myname(), /* client name */
624 account_name, /* machine account name */
625 orig_trust_passwd_hash,
626 sec_channel_type,
627 &neg_flags);
628 if (!NT_STATUS_IS_OK(result)) {
629 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
630 nt_errstr(result)));
631 return result;
635 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
637 if (cli->dc->negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
639 struct netr_CryptPassword new_password;
641 init_netr_CryptPassword(new_trust_pwd_cleartext,
642 cli->dc->session_key,
643 &new_password);
645 result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx,
646 cli->srv_name_slash,
647 cli->dc->account_name,
648 sec_channel_type,
649 cli->dc->computer_name,
650 &clnt_creds,
651 &srv_cred,
652 &new_password);
653 if (!NT_STATUS_IS_OK(result)) {
654 DEBUG(0,("rpccli_netr_ServerPasswordSet2 failed: %s\n",
655 nt_errstr(result)));
656 return result;
658 } else {
660 struct samr_Password new_password;
661 memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash));
662 netlogon_creds_des_encrypt(cli->dc, &new_password);
664 result = rpccli_netr_ServerPasswordSet(cli, mem_ctx,
665 cli->srv_name_slash,
666 cli->dc->account_name,
667 sec_channel_type,
668 cli->dc->computer_name,
669 &clnt_creds,
670 &srv_cred,
671 &new_password);
672 if (!NT_STATUS_IS_OK(result)) {
673 DEBUG(0,("rpccli_netr_ServerPasswordSet failed: %s\n",
674 nt_errstr(result)));
675 return result;
679 /* Always check returned credentials. */
680 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
681 DEBUG(0,("credentials chain check failed\n"));
682 return NT_STATUS_ACCESS_DENIED;
685 return result;