source: branches/samba-3.5.x/source3/rpc_client/cli_netlogon.c

Last change on this file was 596, checked in by Herwig Bauernfeind, 14 years ago

Samba 3.5: Update trunk to 3.5.8

File size: 19.3 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 "../libcli/auth/libcli_auth.h"
25#include "../librpc/gen_ndr/cli_netlogon.h"
26
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****************************************************************************/
32
33NTSTATUS 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)
41{
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;
49
50 if (!ndr_syntax_id_equal(&cli->abstract_syntax,
51 &ndr_table_netlogon.syntax_id)) {
52 return NT_STATUS_INVALID_PARAMETER;
53 }
54
55 TALLOC_FREE(cli->dc);
56
57 /* Store the machine account password we're going to use. */
58 memcpy(password.hash, machine_pwd, 16);
59
60 fstr_sprintf( mach_acct, "%s$", machine_account);
61
62 again:
63 /* Create the client challenge. */
64 generate_random_buffer(clnt_chal_send.data, 8);
65
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;
74 }
75
76 /* Calculate the session key and client credentials */
77
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);
86
87 if (!cli->dc) {
88 return NT_STATUS_NO_MEMORY;
89 }
90
91 /*
92 * Send client auth-2 challenge and receive server repy.
93 */
94
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);
103
104 /* we might be talking to NT4, so let's downgrade in that case and retry
105 * with the returned neg_flags - gd */
106
107 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
108 retried = true;
109 TALLOC_FREE(cli->dc);
110 goto again;
111 }
112
113 if (!NT_STATUS_IS_OK(result)) {
114 return result;
115 }
116
117 /*
118 * Check the returned value using the initial
119 * server received challenge.
120 */
121
122 if (!netlogon_creds_client_check(cli->dc, &srv_chal_recv)) {
123 /*
124 * Server replied with bad credential. Fail.
125 */
126 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
127 "replied with bad credential\n",
128 cli->desthost ));
129 return NT_STATUS_ACCESS_DENIED;
130 }
131
132 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
133 "chain established.\n",
134 cli->desthost ));
135
136 cli->dc->negotiate_flags = neg_flags;
137 *neg_flags_inout = neg_flags;
138
139 return NT_STATUS_OK;
140}
141
142/* Logon domain user */
143
144NTSTATUS 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)
152{
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];
162
163 ZERO_STRUCT(ret_creds);
164 ZERO_STRUCT(zeros);
165
166 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
167 if (!logon) {
168 return NT_STATUS_NO_MEMORY;
169 }
170
171 if (workstation) {
172 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
173 } else {
174 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
175 }
176
177 /* Initialise input parameters */
178
179 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
180
181 switch (logon_type) {
182 case NetlogonInteractiveInformation: {
183
184 struct netr_PasswordInfo *password_info;
185
186 struct samr_Password lmpassword;
187 struct samr_Password ntpassword;
188
189 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
190 if (!password_info) {
191 return NT_STATUS_NO_MEMORY;
192 }
193
194 nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash);
195
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);
202 }
203
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;
210
211 password_info->lmpassword = lmpassword;
212 password_info->ntpassword = ntpassword;
213
214 logon->password = password_info;
215
216 break;
217 }
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;
225
226 ZERO_STRUCT(lm);
227 ZERO_STRUCT(nt);
228
229 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
230 if (!network_info) {
231 return NT_STATUS_NO_MEMORY;
232 }
233
234 generate_random_buffer(chal, 8);
235
236 SMBencrypt(password, chal, local_lm_response);
237 SMBNTencrypt(password, chal, local_nt_response);
238
239 lm.length = 24;
240 lm.data = local_lm_response;
241
242 nt.length = 24;
243 nt.data = local_nt_response;
244
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;
251
252 memcpy(network_info->challenge, chal, 8);
253 network_info->nt = nt;
254 network_info->lm = lm;
255
256 logon->network = network_info;
257
258 break;
259 }
260 default:
261 DEBUG(0, ("switch value %d not supported\n",
262 logon_type));
263 return NT_STATUS_INVALID_INFO_CLASS;
264 }
265
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);
276
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;
281 }
282
283 return result;
284}
285
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); \
290 } \
291} while (0)
292
293static NTSTATUS copy_netr_SamBaseInfo(TALLOC_CTX *mem_ctx,
294 const struct netr_SamBaseInfo *in,
295 struct netr_SamBaseInfo *out)
296{
297 /* first copy all, then realloc pointers */
298 *out = *in;
299
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);
306
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);
313 }
314
315 COPY_LSA_STRING(mem_ctx, in, out, logon_server);
316 COPY_LSA_STRING(mem_ctx, in, out, domain);
317
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);
321 }
322
323 return NT_STATUS_OK;
324}
325
326static 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)
330{
331 struct netr_SamInfo3 *info3;
332 NTSTATUS status;
333
334 if (validation == NULL) {
335 return NT_STATUS_INVALID_PARAMETER;
336 }
337
338 switch (validation_level) {
339 case 3:
340 if (validation->sam3 == NULL) {
341 return NT_STATUS_INVALID_PARAMETER;
342 }
343
344 info3 = talloc_move(mem_ctx, &validation->sam3);
345 break;
346 case 6:
347 if (validation->sam6 == NULL) {
348 return NT_STATUS_INVALID_PARAMETER;
349 }
350
351 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
352 if (info3 == NULL) {
353 return NT_STATUS_NO_MEMORY;
354 }
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;
359 }
360
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;
366 }
367
368 *info3_p = info3;
369
370 return NT_STATUS_OK;
371}
372
373/**
374 * Logon domain user with an 'network' SAM logon
375 *
376 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
377 **/
378
379NTSTATUS 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)
391{
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;
404
405 *info3 = NULL;
406
407 ZERO_STRUCT(zeros);
408 ZERO_STRUCT(ret_creds);
409
410 ZERO_STRUCT(lm);
411 ZERO_STRUCT(nt);
412
413 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
414 if (!logon) {
415 return NT_STATUS_NO_MEMORY;
416 }
417
418 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
419 if (!network_info) {
420 return NT_STATUS_NO_MEMORY;
421 }
422
423 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
424
425 if (server[0] != '\\' && server[1] != '\\') {
426 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
427 } else {
428 server_name_slash = server;
429 }
430
431 if (workstation[0] != '\\' && workstation[1] != '\\') {
432 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
433 } else {
434 workstation_name_slash = workstation;
435 }
436
437 if (!workstation_name_slash || !server_name_slash) {
438 DEBUG(0, ("talloc_asprintf failed!\n"));
439 return NT_STATUS_NO_MEMORY;
440 }
441
442 /* Initialise input parameters */
443
444 lm.data = lm_response.data;
445 lm.length = lm_response.length;
446 nt.data = nt_response.data;
447 nt.length = nt_response.length;
448
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;
455
456 memcpy(network_info->challenge, chal, 8);
457 network_info->nt = nt;
458 network_info->lm = lm;
459
460 logon->network = network_info;
461
462 /* Marshall data and send request */
463
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;
476 }
477
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;
482 }
483
484 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
485
486 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
487 if (!NT_STATUS_IS_OK(result)) {
488 return result;
489 }
490
491 return result;
492}
493
494NTSTATUS 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)
506{
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;
518
519 *info3 = NULL;
520
521 ZERO_STRUCT(zeros);
522
523 ZERO_STRUCT(lm);
524 ZERO_STRUCT(nt);
525
526 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
527 if (!logon) {
528 return NT_STATUS_NO_MEMORY;
529 }
530
531 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
532 if (!network_info) {
533 return NT_STATUS_NO_MEMORY;
534 }
535
536 if (server[0] != '\\' && server[1] != '\\') {
537 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
538 } else {
539 server_name_slash = server;
540 }
541
542 if (workstation[0] != '\\' && workstation[1] != '\\') {
543 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
544 } else {
545 workstation_name_slash = workstation;
546 }
547
548 if (!workstation_name_slash || !server_name_slash) {
549 DEBUG(0, ("talloc_asprintf failed!\n"));
550 return NT_STATUS_NO_MEMORY;
551 }
552
553 /* Initialise input parameters */
554
555 lm.data = lm_response.data;
556 lm.length = lm_response.length;
557 nt.data = nt_response.data;
558 nt.length = nt_response.length;
559
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;
566
567 memcpy(network_info->challenge, chal, 8);
568 network_info->nt = nt;
569 network_info->lm = lm;
570
571 logon->network = network_info;
572
573 /* Marshall data and send request */
574
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;
586 }
587
588 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
589
590 result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
591 if (!NT_STATUS_IS_OK(result)) {
592 return result;
593 }
594
595 return result;
596}
597
598/*********************************************************
599 Change the domain password on the PDC.
600
601 Just changes the password betwen the two values specified.
602
603 Caller must have the cli connected to the netlogon pipe
604 already.
605**********************************************************/
606
607NTSTATUS 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)
614{
615 NTSTATUS result;
616 struct netr_Authenticator clnt_creds, srv_cred;
617
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;
632 }
633 }
634
635 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
636
637 if (cli->dc->negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
638
639 struct netr_CryptPassword new_password;
640
641 init_netr_CryptPassword(new_trust_pwd_cleartext,
642 cli->dc->session_key,
643 &new_password);
644
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;
657 }
658 } else {
659
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);
663
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;
676 }
677 }
678
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;
683 }
684
685 return result;
686}
687
Note: See TracBrowser for help on using the repository browser.