source: branches/samba-3.2.x/source/rpc_client/cli_netlogon.c

Last change on this file was 141, checked in by Paul Smedley, 17 years ago

Update trunk to 3.2.1

File size: 17.0 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
25/* LSA Request Challenge. Sends our challenge to server, then gets
26 server response. These are used to generate the credentials.
27 The sent and received challenges are stored in the netlog pipe
28 private data. Only call this via rpccli_netlogon_setup_creds(). JRA.
29*/
30
31/* instead of rpccli_net_req_chal() we use rpccli_netr_ServerReqChallenge() now - gd */
32
33#if 0
34/****************************************************************************
35LSA Authenticate 2
36
37Send the client credential, receive back a server credential.
38Ensure that the server credential returned matches the session key
39encrypt of the server challenge originally received. JRA.
40****************************************************************************/
41
42 NTSTATUS rpccli_net_auth2(struct rpc_pipe_client *cli,
43 uint16 sec_chan,
44 uint32 *neg_flags, DOM_CHAL *srv_chal)
45{
46 prs_struct qbuf, rbuf;
47 NET_Q_AUTH_2 q;
48 NET_R_AUTH_2 r;
49 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
50 fstring machine_acct;
51
52 if ( sec_chan == SEC_CHAN_DOMAIN )
53 fstr_sprintf( machine_acct, "%s$", lp_workgroup() );
54 else
55 fstrcpy( machine_acct, cli->mach_acct );
56
57 /* create and send a MSRPC command with api NET_AUTH2 */
58
59 DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
60 cli->srv_name_slash, machine_acct, sec_chan, global_myname(),
61 credstr(cli->clnt_cred.challenge.data), *neg_flags));
62
63 /* store the parameters */
64
65 init_q_auth_2(&q, cli->srv_name_slash, machine_acct,
66 sec_chan, global_myname(), &cli->clnt_cred.challenge,
67 *neg_flags);
68
69 /* turn parameters into data stream */
70
71 CLI_DO_RPC(cli, mem_ctx, PI_NETLOGON, NET_AUTH2,
72 q, r,
73 qbuf, rbuf,
74 net_io_q_auth_2,
75 net_io_r_auth_2,
76 NT_STATUS_UNSUCCESSFUL);
77
78 result = r.status;
79
80 if (NT_STATUS_IS_OK(result)) {
81 UTIME zerotime;
82
83 /*
84 * Check the returned value using the initial
85 * server received challenge.
86 */
87
88 zerotime.time = 0;
89 if (cred_assert( &r.srv_chal, cli->sess_key, srv_chal, zerotime) == 0) {
90
91 /*
92 * Server replied with bad credential. Fail.
93 */
94 DEBUG(0,("cli_net_auth2: server %s replied with bad credential (bad machine \
95password ?).\n", cli->cli->desthost ));
96 return NT_STATUS_ACCESS_DENIED;
97 }
98 *neg_flags = r.srv_flgs.neg_flags;
99 }
100
101 return result;
102}
103#endif
104
105/****************************************************************************
106 LSA Authenticate 2
107
108 Send the client credential, receive back a server credential.
109 The caller *must* ensure that the server credential returned matches the session key
110 encrypt of the server challenge originally received. JRA.
111****************************************************************************/
112
113/* instead of rpccli_net_auth2() we use rpccli_netr_ServerAuthenticate2() now - gd */
114
115
116/****************************************************************************
117 Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
118 credentials chain. Stores the credentials in the struct dcinfo in the
119 netlogon pipe struct.
120****************************************************************************/
121
122NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
123 const char *server_name,
124 const char *domain,
125 const char *clnt_name,
126 const char *machine_account,
127 const unsigned char machine_pwd[16],
128 enum netr_SchannelType sec_chan_type,
129 uint32_t *neg_flags_inout)
130{
131 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
132 struct netr_Credential clnt_chal_send;
133 struct netr_Credential srv_chal_recv;
134 struct dcinfo *dc;
135 bool retried = false;
136
137 SMB_ASSERT(cli->pipe_idx == PI_NETLOGON);
138
139 dc = cli->dc;
140 if (!dc) {
141 return NT_STATUS_INVALID_PARAMETER;
142 }
143
144 /* Ensure we don't reuse any of this state. */
145 ZERO_STRUCTP(dc);
146
147 /* Store the machine account password we're going to use. */
148 memcpy(dc->mach_pw, machine_pwd, 16);
149
150 fstrcpy(dc->remote_machine, "\\\\");
151 fstrcat(dc->remote_machine, server_name);
152
153 fstrcpy(dc->domain, domain);
154
155 fstr_sprintf( dc->mach_acct, "%s$", machine_account);
156
157 again:
158 /* Create the client challenge. */
159 generate_random_buffer(clnt_chal_send.data, 8);
160
161 /* Get the server challenge. */
162 result = rpccli_netr_ServerReqChallenge(cli, cli->mem_ctx,
163 dc->remote_machine,
164 clnt_name,
165 &clnt_chal_send,
166 &srv_chal_recv);
167 if (!NT_STATUS_IS_OK(result)) {
168 return result;
169 }
170
171 /* Calculate the session key and client credentials */
172 creds_client_init(*neg_flags_inout,
173 dc,
174 &clnt_chal_send,
175 &srv_chal_recv,
176 machine_pwd,
177 &clnt_chal_send);
178
179 /*
180 * Send client auth-2 challenge and receive server repy.
181 */
182
183 result = rpccli_netr_ServerAuthenticate2(cli, cli->mem_ctx,
184 dc->remote_machine,
185 dc->mach_acct,
186 sec_chan_type,
187 clnt_name,
188 &clnt_chal_send, /* input. */
189 &srv_chal_recv, /* output. */
190 neg_flags_inout);
191
192 /* we might be talking to NT4, so let's downgrade in that case and retry
193 * with the returned neg_flags - gd */
194
195 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
196 retried = true;
197 goto again;
198 }
199
200 if (!NT_STATUS_IS_OK(result)) {
201 return result;
202 }
203
204 /*
205 * Check the returned value using the initial
206 * server received challenge.
207 */
208
209 if (!netlogon_creds_client_check(dc, &srv_chal_recv)) {
210 /*
211 * Server replied with bad credential. Fail.
212 */
213 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
214 "replied with bad credential\n",
215 cli->cli->desthost ));
216 return NT_STATUS_ACCESS_DENIED;
217 }
218
219 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
220 "chain established.\n",
221 cli->cli->desthost ));
222
223 return NT_STATUS_OK;
224}
225
226/* Logon domain user */
227
228NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
229 TALLOC_CTX *mem_ctx,
230 uint32 logon_parameters,
231 const char *domain,
232 const char *username,
233 const char *password,
234 const char *workstation,
235 int logon_type)
236{
237 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
238 struct netr_Authenticator clnt_creds;
239 struct netr_Authenticator ret_creds;
240 union netr_LogonInfo *logon;
241 union netr_Validation validation;
242 uint8_t authoritative;
243 int validation_level = 3;
244 fstring clnt_name_slash;
245 uint8 zeros[16];
246
247 ZERO_STRUCT(ret_creds);
248 ZERO_STRUCT(zeros);
249
250 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
251 if (!logon) {
252 return NT_STATUS_NO_MEMORY;
253 }
254
255 if (workstation) {
256 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
257 } else {
258 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
259 }
260
261 /* Initialise input parameters */
262
263 netlogon_creds_client_step(cli->dc, &clnt_creds);
264
265 switch (logon_type) {
266 case INTERACTIVE_LOGON_TYPE: {
267
268 struct netr_PasswordInfo *password_info;
269
270 struct samr_Password lmpassword;
271 struct samr_Password ntpassword;
272
273 unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16];
274
275 unsigned char lm_owf[16];
276 unsigned char nt_owf[16];
277 unsigned char key[16];
278
279 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
280 if (!password_info) {
281 return NT_STATUS_NO_MEMORY;
282 }
283
284 nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd);
285
286#ifdef DEBUG_PASSWORD
287 DEBUG(100,("lm cypher:"));
288 dump_data(100, lm_owf_user_pwd, 16);
289
290 DEBUG(100,("nt cypher:"));
291 dump_data(100, nt_owf_user_pwd, 16);
292#endif
293 memset(key, 0, 16);
294 memcpy(key, cli->dc->sess_key, 8);
295
296 memcpy(lm_owf, lm_owf_user_pwd, 16);
297 SamOEMhash(lm_owf, key, 16);
298 memcpy(nt_owf, nt_owf_user_pwd, 16);
299 SamOEMhash(nt_owf, key, 16);
300
301#ifdef DEBUG_PASSWORD
302 DEBUG(100,("encrypt of lm owf password:"));
303 dump_data(100, lm_owf, 16);
304
305 DEBUG(100,("encrypt of nt owf password:"));
306 dump_data(100, nt_owf, 16);
307#endif
308 memcpy(lmpassword.hash, lm_owf, 16);
309 memcpy(ntpassword.hash, nt_owf, 16);
310
311 init_netr_PasswordInfo(password_info,
312 domain,
313 logon_parameters,
314 0xdead,
315 0xbeef,
316 username,
317 clnt_name_slash,
318 lmpassword,
319 ntpassword);
320
321 logon->password = password_info;
322
323 break;
324 }
325 case NET_LOGON_TYPE: {
326 struct netr_NetworkInfo *network_info;
327 uint8 chal[8];
328 unsigned char local_lm_response[24];
329 unsigned char local_nt_response[24];
330 struct netr_ChallengeResponse lm;
331 struct netr_ChallengeResponse nt;
332
333 ZERO_STRUCT(lm);
334 ZERO_STRUCT(nt);
335
336 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
337 if (!network_info) {
338 return NT_STATUS_NO_MEMORY;
339 }
340
341 generate_random_buffer(chal, 8);
342
343 SMBencrypt(password, chal, local_lm_response);
344 SMBNTencrypt(password, chal, local_nt_response);
345
346 lm.length = 24;
347 lm.data = local_lm_response;
348
349 nt.length = 24;
350 nt.data = local_nt_response;
351
352 init_netr_NetworkInfo(network_info,
353 domain,
354 logon_parameters,
355 0xdead,
356 0xbeef,
357 username,
358 clnt_name_slash,
359 chal,
360 nt,
361 lm);
362
363 logon->network = network_info;
364
365 break;
366 }
367 default:
368 DEBUG(0, ("switch value %d not supported\n",
369 logon_type));
370 return NT_STATUS_INVALID_INFO_CLASS;
371 }
372
373 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
374 cli->dc->remote_machine,
375 global_myname(),
376 &clnt_creds,
377 &ret_creds,
378 logon_type,
379 logon,
380 validation_level,
381 &validation,
382 &authoritative);
383
384 if (memcmp(zeros, &ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
385 /* Check returned credentials if present. */
386 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
387 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
388 return NT_STATUS_ACCESS_DENIED;
389 }
390 }
391
392 return result;
393}
394
395
396/**
397 * Logon domain user with an 'network' SAM logon
398 *
399 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
400 **/
401
402NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
403 TALLOC_CTX *mem_ctx,
404 uint32 logon_parameters,
405 const char *server,
406 const char *username,
407 const char *domain,
408 const char *workstation,
409 const uint8 chal[8],
410 DATA_BLOB lm_response,
411 DATA_BLOB nt_response,
412 struct netr_SamInfo3 **info3)
413{
414 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
415 int validation_level = 3;
416 const char *workstation_name_slash;
417 const char *server_name_slash;
418 uint8 zeros[16];
419 struct netr_Authenticator clnt_creds;
420 struct netr_Authenticator ret_creds;
421 union netr_LogonInfo *logon = NULL;
422 struct netr_NetworkInfo *network_info;
423 uint8_t authoritative;
424 union netr_Validation validation;
425 struct netr_ChallengeResponse lm;
426 struct netr_ChallengeResponse nt;
427
428 *info3 = NULL;
429
430 ZERO_STRUCT(zeros);
431 ZERO_STRUCT(ret_creds);
432
433 ZERO_STRUCT(lm);
434 ZERO_STRUCT(nt);
435
436 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
437 if (!logon) {
438 return NT_STATUS_NO_MEMORY;
439 }
440
441 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
442 if (!network_info) {
443 return NT_STATUS_NO_MEMORY;
444 }
445
446 netlogon_creds_client_step(cli->dc, &clnt_creds);
447
448 if (server[0] != '\\' && server[1] != '\\') {
449 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
450 } else {
451 server_name_slash = server;
452 }
453
454 if (workstation[0] != '\\' && workstation[1] != '\\') {
455 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
456 } else {
457 workstation_name_slash = workstation;
458 }
459
460 if (!workstation_name_slash || !server_name_slash) {
461 DEBUG(0, ("talloc_asprintf failed!\n"));
462 return NT_STATUS_NO_MEMORY;
463 }
464
465 /* Initialise input parameters */
466
467 lm.data = lm_response.data;
468 lm.length = lm_response.length;
469 nt.data = nt_response.data;
470 nt.length = nt_response.length;
471
472 init_netr_NetworkInfo(network_info,
473 domain,
474 logon_parameters,
475 0xdead,
476 0xbeef,
477 username,
478 workstation_name_slash,
479 (uint8_t *) chal,
480 nt,
481 lm);
482
483 logon->network = network_info;
484
485 /* Marshall data and send request */
486
487 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
488 server_name_slash,
489 global_myname(),
490 &clnt_creds,
491 &ret_creds,
492 NET_LOGON_TYPE,
493 logon,
494 validation_level,
495 &validation,
496 &authoritative);
497 if (!NT_STATUS_IS_OK(result)) {
498 return result;
499 }
500
501 if (memcmp(zeros, validation.sam3->base.key.key, 16) != 0) {
502 SamOEMhash(validation.sam3->base.key.key,
503 cli->dc->sess_key, 16);
504 }
505
506 if (memcmp(zeros, validation.sam3->base.LMSessKey.key, 8) != 0) {
507 SamOEMhash(validation.sam3->base.LMSessKey.key,
508 cli->dc->sess_key, 8);
509 }
510
511 if (memcmp(zeros, ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
512 /* Check returned credentials if present. */
513 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
514 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
515 return NT_STATUS_ACCESS_DENIED;
516 }
517 }
518
519 *info3 = validation.sam3;
520
521 return result;
522}
523
524NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
525 TALLOC_CTX *mem_ctx,
526 uint32 logon_parameters,
527 const char *server,
528 const char *username,
529 const char *domain,
530 const char *workstation,
531 const uint8 chal[8],
532 DATA_BLOB lm_response,
533 DATA_BLOB nt_response,
534 struct netr_SamInfo3 **info3)
535{
536 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
537 int validation_level = 3;
538 const char *workstation_name_slash;
539 const char *server_name_slash;
540 uint8 zeros[16];
541 union netr_LogonInfo *logon = NULL;
542 struct netr_NetworkInfo *network_info;
543 uint8_t authoritative;
544 union netr_Validation validation;
545 struct netr_ChallengeResponse lm;
546 struct netr_ChallengeResponse nt;
547 uint32_t flags = 0;
548
549 *info3 = NULL;
550
551 ZERO_STRUCT(zeros);
552
553 ZERO_STRUCT(lm);
554 ZERO_STRUCT(nt);
555
556 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
557 if (!logon) {
558 return NT_STATUS_NO_MEMORY;
559 }
560
561 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
562 if (!network_info) {
563 return NT_STATUS_NO_MEMORY;
564 }
565
566 if (server[0] != '\\' && server[1] != '\\') {
567 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
568 } else {
569 server_name_slash = server;
570 }
571
572 if (workstation[0] != '\\' && workstation[1] != '\\') {
573 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
574 } else {
575 workstation_name_slash = workstation;
576 }
577
578 if (!workstation_name_slash || !server_name_slash) {
579 DEBUG(0, ("talloc_asprintf failed!\n"));
580 return NT_STATUS_NO_MEMORY;
581 }
582
583 /* Initialise input parameters */
584
585 lm.data = lm_response.data;
586 lm.length = lm_response.length;
587 nt.data = nt_response.data;
588 nt.length = nt_response.length;
589
590 init_netr_NetworkInfo(network_info,
591 domain,
592 logon_parameters,
593 0xdead,
594 0xbeef,
595 username,
596 workstation_name_slash,
597 (uint8_t *) chal,
598 nt,
599 lm);
600
601 logon->network = network_info;
602
603 /* Marshall data and send request */
604
605 result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
606 server_name_slash,
607 global_myname(),
608 NET_LOGON_TYPE,
609 logon,
610 validation_level,
611 &validation,
612 &authoritative,
613 &flags);
614 if (!NT_STATUS_IS_OK(result)) {
615 return result;
616 }
617
618 if (memcmp(zeros, validation.sam3->base.key.key, 16) != 0) {
619 SamOEMhash(validation.sam3->base.key.key,
620 cli->dc->sess_key, 16);
621 }
622
623 if (memcmp(zeros, validation.sam3->base.LMSessKey.key, 8) != 0) {
624 SamOEMhash(validation.sam3->base.LMSessKey.key,
625 cli->dc->sess_key, 8);
626 }
627
628 *info3 = validation.sam3;
629
630 return result;
631}
Note: See TracBrowser for help on using the repository browser.