source: trunk/server/source3/rpc_client/cli_netlogon.c

Last change on this file was 862, checked in by Silvan Scherrer, 11 years ago

Samba Server: update trunk to 3.6.23

File size: 18.7 KB
Line 
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.
8
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.
13
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.
18
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/>.
21*/
22
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"
31
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****************************************************************************/
37
38NTSTATUS 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)
46{
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;
56
57 if (!ndr_syntax_id_equal(&cli->abstract_syntax,
58 &ndr_table_netlogon.syntax_id)) {
59 return NT_STATUS_INVALID_PARAMETER;
60 }
61
62 TALLOC_FREE(cli->dc);
63
64 /* Store the machine account password we're going to use. */
65 memcpy(password.hash, machine_pwd, 16);
66
67 fstr_sprintf( mach_acct, "%s$", machine_account);
68
69 again:
70 /* Create the client challenge. */
71 generate_random_buffer(clnt_chal_send.data, 8);
72
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;
82 }
83 if (!NT_STATUS_IS_OK(result)) {
84 return result;
85 }
86
87 /* Calculate the session key and client credentials */
88
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);
97
98 if (!cli->dc) {
99 return NT_STATUS_NO_MEMORY;
100 }
101
102 /*
103 * Send client auth-2 challenge and receive server repy.
104 */
105
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;
117 }
118 /* we might be talking to NT4, so let's downgrade in that case and retry
119 * with the returned neg_flags - gd */
120
121 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
122 retried = true;
123 TALLOC_FREE(cli->dc);
124 goto again;
125 }
126
127 if (!NT_STATUS_IS_OK(result)) {
128 return result;
129 }
130
131 /*
132 * Check the returned value using the initial
133 * server received challenge.
134 */
135
136 if (!netlogon_creds_client_check(cli->dc, &srv_chal_recv)) {
137 /*
138 * Server replied with bad credential. Fail.
139 */
140 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
141 "replied with bad credential\n",
142 cli->desthost ));
143 return NT_STATUS_ACCESS_DENIED;
144 }
145
146 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
147 "chain established.\n",
148 cli->desthost ));
149
150 cli->dc->negotiate_flags = neg_flags;
151 *neg_flags_inout = neg_flags;
152
153 return NT_STATUS_OK;
154}
155
156/* Logon domain user */
157
158NTSTATUS 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)
167{
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;
177
178 ZERO_STRUCT(ret_creds);
179
180 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
181 if (!logon) {
182 return NT_STATUS_NO_MEMORY;
183 }
184
185 if (workstation) {
186 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
187 } else {
188 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
189 }
190
191 /* Initialise input parameters */
192
193 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
194
195 switch (logon_type) {
196 case NetlogonInteractiveInformation: {
197
198 struct netr_PasswordInfo *password_info;
199
200 struct samr_Password lmpassword;
201 struct samr_Password ntpassword;
202
203 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
204 if (!password_info) {
205 return NT_STATUS_NO_MEMORY;
206 }
207
208 nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash);
209
210 if (cli->dc->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
211 netlogon_creds_arcfour_crypt(cli->dc, lmpassword.hash, 16);
212 netlogon_creds_arcfour_crypt(cli->dc, ntpassword.hash, 16);
213 } else {
214 netlogon_creds_des_encrypt(cli->dc, &lmpassword);
215 netlogon_creds_des_encrypt(cli->dc, &ntpassword);
216 }
217
218 password_info->identity_info.domain_name.string = domain;
219 password_info->identity_info.parameter_control = logon_parameters;
220 password_info->identity_info.logon_id_low = 0xdead;
221 password_info->identity_info.logon_id_high = 0xbeef;
222 password_info->identity_info.account_name.string = username;
223 password_info->identity_info.workstation.string = clnt_name_slash;
224
225 password_info->lmpassword = lmpassword;
226 password_info->ntpassword = ntpassword;
227
228 logon->password = password_info;
229
230 break;
231 }
232 case NetlogonNetworkInformation: {
233 struct netr_NetworkInfo *network_info;
234 uint8 chal[8];
235 unsigned char local_lm_response[24];
236 unsigned char local_nt_response[24];
237 struct netr_ChallengeResponse lm;
238 struct netr_ChallengeResponse nt;
239
240 ZERO_STRUCT(lm);
241 ZERO_STRUCT(nt);
242
243 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
244 if (!network_info) {
245 return NT_STATUS_NO_MEMORY;
246 }
247
248 generate_random_buffer(chal, 8);
249
250 SMBencrypt(password, chal, local_lm_response);
251 SMBNTencrypt(password, chal, local_nt_response);
252
253 lm.length = 24;
254 lm.data = local_lm_response;
255
256 nt.length = 24;
257 nt.data = local_nt_response;
258
259 network_info->identity_info.domain_name.string = domain;
260 network_info->identity_info.parameter_control = logon_parameters;
261 network_info->identity_info.logon_id_low = 0xdead;
262 network_info->identity_info.logon_id_high = 0xbeef;
263 network_info->identity_info.account_name.string = username;
264 network_info->identity_info.workstation.string = clnt_name_slash;
265
266 memcpy(network_info->challenge, chal, 8);
267 network_info->nt = nt;
268 network_info->lm = lm;
269
270 logon->network = network_info;
271
272 break;
273 }
274 default:
275 DEBUG(0, ("switch value %d not supported\n",
276 logon_type));
277 return NT_STATUS_INVALID_INFO_CLASS;
278 }
279
280 status = dcerpc_netr_LogonSamLogon(b, mem_ctx,
281 cli->srv_name_slash,
282 global_myname(),
283 &clnt_creds,
284 &ret_creds,
285 logon_type,
286 logon,
287 validation_level,
288 &validation,
289 &authoritative,
290 &result);
291 if (!NT_STATUS_IS_OK(status)) {
292 return status;
293 }
294
295 /* Always check returned credentials */
296 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
297 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
298 return NT_STATUS_ACCESS_DENIED;
299 }
300
301 return result;
302}
303
304static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
305 uint16_t validation_level,
306 union netr_Validation *validation,
307 struct netr_SamInfo3 **info3_p)
308{
309 struct netr_SamInfo3 *info3;
310 NTSTATUS status;
311
312 if (validation == NULL) {
313 return NT_STATUS_INVALID_PARAMETER;
314 }
315
316 switch (validation_level) {
317 case 3:
318 if (validation->sam3 == NULL) {
319 return NT_STATUS_INVALID_PARAMETER;
320 }
321
322 info3 = talloc_move(mem_ctx, &validation->sam3);
323 break;
324 case 6:
325 if (validation->sam6 == NULL) {
326 return NT_STATUS_INVALID_PARAMETER;
327 }
328
329 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
330 if (info3 == NULL) {
331 return NT_STATUS_NO_MEMORY;
332 }
333 status = copy_netr_SamBaseInfo(info3, &validation->sam6->base, &info3->base);
334 if (!NT_STATUS_IS_OK(status)) {
335 TALLOC_FREE(info3);
336 return status;
337 }
338
339 info3->sidcount = validation->sam6->sidcount;
340 info3->sids = talloc_move(info3, &validation->sam6->sids);
341 break;
342 default:
343 return NT_STATUS_BAD_VALIDATION_CLASS;
344 }
345
346 *info3_p = info3;
347
348 return NT_STATUS_OK;
349}
350
351/**
352 * Logon domain user with an 'network' SAM logon
353 *
354 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
355 **/
356
357NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
358 TALLOC_CTX *mem_ctx,
359 uint32 logon_parameters,
360 const char *server,
361 const char *username,
362 const char *domain,
363 const char *workstation,
364 const uint8 chal[8],
365 uint16_t validation_level,
366 DATA_BLOB lm_response,
367 DATA_BLOB nt_response,
368 struct netr_SamInfo3 **info3)
369{
370 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
371 NTSTATUS status;
372 const char *workstation_name_slash;
373 const char *server_name_slash;
374 struct netr_Authenticator clnt_creds;
375 struct netr_Authenticator ret_creds;
376 union netr_LogonLevel *logon = NULL;
377 struct netr_NetworkInfo *network_info;
378 uint8_t authoritative;
379 union netr_Validation validation;
380 struct netr_ChallengeResponse lm;
381 struct netr_ChallengeResponse nt;
382 struct dcerpc_binding_handle *b = cli->binding_handle;
383
384 *info3 = NULL;
385
386 ZERO_STRUCT(ret_creds);
387
388 ZERO_STRUCT(lm);
389 ZERO_STRUCT(nt);
390
391 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
392 if (!logon) {
393 return NT_STATUS_NO_MEMORY;
394 }
395
396 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
397 if (!network_info) {
398 return NT_STATUS_NO_MEMORY;
399 }
400
401 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
402
403 if (server[0] != '\\' && server[1] != '\\') {
404 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
405 } else {
406 server_name_slash = server;
407 }
408
409 if (workstation[0] != '\\' && workstation[1] != '\\') {
410 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
411 } else {
412 workstation_name_slash = workstation;
413 }
414
415 if (!workstation_name_slash || !server_name_slash) {
416 DEBUG(0, ("talloc_asprintf failed!\n"));
417 return NT_STATUS_NO_MEMORY;
418 }
419
420 /* Initialise input parameters */
421
422 lm.data = lm_response.data;
423 lm.length = lm_response.length;
424 nt.data = nt_response.data;
425 nt.length = nt_response.length;
426
427 network_info->identity_info.domain_name.string = domain;
428 network_info->identity_info.parameter_control = logon_parameters;
429 network_info->identity_info.logon_id_low = 0xdead;
430 network_info->identity_info.logon_id_high = 0xbeef;
431 network_info->identity_info.account_name.string = username;
432 network_info->identity_info.workstation.string = workstation_name_slash;
433
434 memcpy(network_info->challenge, chal, 8);
435 network_info->nt = nt;
436 network_info->lm = lm;
437
438 logon->network = network_info;
439
440 /* Marshall data and send request */
441
442 status = dcerpc_netr_LogonSamLogon(b, mem_ctx,
443 server_name_slash,
444 global_myname(),
445 &clnt_creds,
446 &ret_creds,
447 NetlogonNetworkInformation,
448 logon,
449 validation_level,
450 &validation,
451 &authoritative,
452 &result);
453 if (!NT_STATUS_IS_OK(status)) {
454 return status;
455 }
456
457 /* Always check returned credentials. */
458 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
459 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
460 return NT_STATUS_ACCESS_DENIED;
461 }
462
463 if (!NT_STATUS_IS_OK(result)) {
464 return result;
465 }
466
467 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
468
469 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
470 if (!NT_STATUS_IS_OK(result)) {
471 return result;
472 }
473
474 return result;
475}
476
477NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
478 TALLOC_CTX *mem_ctx,
479 uint32 logon_parameters,
480 const char *server,
481 const char *username,
482 const char *domain,
483 const char *workstation,
484 const uint8 chal[8],
485 uint16_t validation_level,
486 DATA_BLOB lm_response,
487 DATA_BLOB nt_response,
488 struct netr_SamInfo3 **info3)
489{
490 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
491 NTSTATUS status;
492 const char *workstation_name_slash;
493 const char *server_name_slash;
494 union netr_LogonLevel *logon = NULL;
495 struct netr_NetworkInfo *network_info;
496 uint8_t authoritative;
497 union netr_Validation validation;
498 struct netr_ChallengeResponse lm;
499 struct netr_ChallengeResponse nt;
500 uint32_t flags = 0;
501 struct dcerpc_binding_handle *b = cli->binding_handle;
502
503 *info3 = NULL;
504
505 ZERO_STRUCT(lm);
506 ZERO_STRUCT(nt);
507
508 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
509 if (!logon) {
510 return NT_STATUS_NO_MEMORY;
511 }
512
513 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
514 if (!network_info) {
515 return NT_STATUS_NO_MEMORY;
516 }
517
518 if (server[0] != '\\' && server[1] != '\\') {
519 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
520 } else {
521 server_name_slash = server;
522 }
523
524 if (workstation[0] != '\\' && workstation[1] != '\\') {
525 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
526 } else {
527 workstation_name_slash = workstation;
528 }
529
530 if (!workstation_name_slash || !server_name_slash) {
531 DEBUG(0, ("talloc_asprintf failed!\n"));
532 return NT_STATUS_NO_MEMORY;
533 }
534
535 /* Initialise input parameters */
536
537 lm.data = lm_response.data;
538 lm.length = lm_response.length;
539 nt.data = nt_response.data;
540 nt.length = nt_response.length;
541
542 network_info->identity_info.domain_name.string = domain;
543 network_info->identity_info.parameter_control = logon_parameters;
544 network_info->identity_info.logon_id_low = 0xdead;
545 network_info->identity_info.logon_id_high = 0xbeef;
546 network_info->identity_info.account_name.string = username;
547 network_info->identity_info.workstation.string = workstation_name_slash;
548
549 memcpy(network_info->challenge, chal, 8);
550 network_info->nt = nt;
551 network_info->lm = lm;
552
553 logon->network = network_info;
554
555 /* Marshall data and send request */
556
557 status = dcerpc_netr_LogonSamLogonEx(b, mem_ctx,
558 server_name_slash,
559 global_myname(),
560 NetlogonNetworkInformation,
561 logon,
562 validation_level,
563 &validation,
564 &authoritative,
565 &flags,
566 &result);
567 if (!NT_STATUS_IS_OK(status)) {
568 return status;
569 }
570
571 if (!NT_STATUS_IS_OK(result)) {
572 return result;
573 }
574
575 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
576
577 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
578 if (!NT_STATUS_IS_OK(result)) {
579 return result;
580 }
581
582 return result;
583}
584
585/*********************************************************
586 Change the domain password on the PDC.
587
588 Just changes the password betwen the two values specified.
589
590 Caller must have the cli connected to the netlogon pipe
591 already.
592**********************************************************/
593
594NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
595 TALLOC_CTX *mem_ctx,
596 const char *account_name,
597 const unsigned char orig_trust_passwd_hash[16],
598 const char *new_trust_pwd_cleartext,
599 const unsigned char new_trust_passwd_hash[16],
600 enum netr_SchannelType sec_channel_type)
601{
602 NTSTATUS result, status;
603 struct netr_Authenticator clnt_creds, srv_cred;
604 struct dcerpc_binding_handle *b = cli->binding_handle;
605
606 if (!cli->dc) {
607 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
608 result = rpccli_netlogon_setup_creds(cli,
609 cli->desthost, /* server name */
610 lp_workgroup(), /* domain */
611 global_myname(), /* client name */
612 account_name, /* machine account name */
613 orig_trust_passwd_hash,
614 sec_channel_type,
615 &neg_flags);
616 if (!NT_STATUS_IS_OK(result)) {
617 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
618 nt_errstr(result)));
619 return result;
620 }
621 }
622
623 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
624
625 if (cli->dc->negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
626
627 struct netr_CryptPassword new_password;
628 uint32_t old_timeout;
629
630 init_netr_CryptPassword(new_trust_pwd_cleartext,
631 cli->dc->session_key,
632 &new_password);
633
634 old_timeout = dcerpc_binding_handle_set_timeout(b, 600000);
635
636 status = dcerpc_netr_ServerPasswordSet2(b, mem_ctx,
637 cli->srv_name_slash,
638 cli->dc->account_name,
639 sec_channel_type,
640 cli->dc->computer_name,
641 &clnt_creds,
642 &srv_cred,
643 &new_password,
644 &result);
645
646 dcerpc_binding_handle_set_timeout(b, old_timeout);
647
648 if (!NT_STATUS_IS_OK(status)) {
649 DEBUG(0,("dcerpc_netr_ServerPasswordSet2 failed: %s\n",
650 nt_errstr(status)));
651 return status;
652 }
653 } else {
654
655 struct samr_Password new_password;
656 uint32_t old_timeout;
657
658 memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash));
659 netlogon_creds_des_encrypt(cli->dc, &new_password);
660
661 old_timeout = dcerpc_binding_handle_set_timeout(b, 600000);
662
663 status = dcerpc_netr_ServerPasswordSet(b, mem_ctx,
664 cli->srv_name_slash,
665 cli->dc->account_name,
666 sec_channel_type,
667 cli->dc->computer_name,
668 &clnt_creds,
669 &srv_cred,
670 &new_password,
671 &result);
672
673 dcerpc_binding_handle_set_timeout(b, old_timeout);
674
675 if (!NT_STATUS_IS_OK(status)) {
676 DEBUG(0,("dcerpc_netr_ServerPasswordSet failed: %s\n",
677 nt_errstr(status)));
678 return status;
679 }
680 }
681
682 /* Always check returned credentials. */
683 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
684 DEBUG(0,("credentials chain check failed\n"));
685 return NT_STATUS_ACCESS_DENIED;
686 }
687
688 if (!NT_STATUS_IS_OK(result)) {
689 DEBUG(0,("dcerpc_netr_ServerPasswordSet{2} failed: %s\n",
690 nt_errstr(result)));
691 return result;
692 }
693
694 return result;
695}
696
Note: See TracBrowser for help on using the repository browser.