Fix bug #6254 - PUT/GET produces an error in IPv6 to a smb-server(3.3)
[Samba.git] / source / rpc_client / cli_netlogon.c
blobde45e714eb7a432bf088e1d47efae8fb2a0ed9f1
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"
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.
31 /* instead of rpccli_net_req_chal() we use rpccli_netr_ServerReqChallenge() now - gd */
33 #if 0
34 /****************************************************************************
35 LSA Authenticate 2
37 Send the client credential, receive back a server credential.
38 Ensure that the server credential returned matches the session key
39 encrypt of the server challenge originally received. JRA.
40 ****************************************************************************/
42 NTSTATUS rpccli_net_auth2(struct rpc_pipe_client *cli,
43 uint16 sec_chan,
44 uint32 *neg_flags, DOM_CHAL *srv_chal)
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;
52 if ( sec_chan == SEC_CHAN_DOMAIN )
53 fstr_sprintf( machine_acct, "%s$", lp_workgroup() );
54 else
55 fstrcpy( machine_acct, cli->mach_acct );
57 /* create and send a MSRPC command with api NET_AUTH2 */
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));
63 /* store the parameters */
65 init_q_auth_2(&q, cli->srv_name_slash, machine_acct,
66 sec_chan, global_myname(), &cli->clnt_cred.challenge,
67 *neg_flags);
69 /* turn parameters into data stream */
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);
78 result = r.status;
80 if (NT_STATUS_IS_OK(result)) {
81 UTIME zerotime;
84 * Check the returned value using the initial
85 * server received challenge.
88 zerotime.time = 0;
89 if (cred_assert( &r.srv_chal, cli->sess_key, srv_chal, zerotime) == 0) {
92 * Server replied with bad credential. Fail.
94 DEBUG(0,("cli_net_auth2: server %s replied with bad credential (bad machine \
95 password ?).\n", cli->cli->desthost ));
96 return NT_STATUS_ACCESS_DENIED;
98 *neg_flags = r.srv_flgs.neg_flags;
101 return result;
103 #endif
105 /****************************************************************************
106 LSA Authenticate 2
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 ****************************************************************************/
113 /* instead of rpccli_net_auth2() we use rpccli_netr_ServerAuthenticate2() now - gd */
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 ****************************************************************************/
122 NTSTATUS 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)
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;
137 SMB_ASSERT(cli->pipe_idx == PI_NETLOGON);
139 dc = cli->dc;
140 if (!dc) {
141 return NT_STATUS_INVALID_PARAMETER;
144 /* Ensure we don't reuse any of this state. */
145 ZERO_STRUCTP(dc);
147 /* Store the machine account password we're going to use. */
148 memcpy(dc->mach_pw, machine_pwd, 16);
150 fstrcpy(dc->remote_machine, "\\\\");
151 fstrcat(dc->remote_machine, server_name);
153 fstrcpy(dc->domain, domain);
155 fstr_sprintf( dc->mach_acct, "%s$", machine_account);
157 again:
158 /* Create the client challenge. */
159 generate_random_buffer(clnt_chal_send.data, 8);
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;
171 /* Calculate the session key and client credentials */
172 creds_client_init(*neg_flags_inout,
174 &clnt_chal_send,
175 &srv_chal_recv,
176 machine_pwd,
177 &clnt_chal_send);
180 * Send client auth-2 challenge and receive server repy.
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);
192 /* we might be talking to NT4, so let's downgrade in that case and retry
193 * with the returned neg_flags - gd */
195 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
196 retried = true;
197 goto again;
200 if (!NT_STATUS_IS_OK(result)) {
201 return result;
205 * Check the returned value using the initial
206 * server received challenge.
209 if (!netlogon_creds_client_check(dc, &srv_chal_recv)) {
211 * Server replied with bad credential. Fail.
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;
219 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
220 "chain established.\n",
221 cli->cli->desthost ));
223 return NT_STATUS_OK;
226 /* Logon domain user */
228 NTSTATUS 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)
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];
247 ZERO_STRUCT(ret_creds);
248 ZERO_STRUCT(zeros);
250 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
251 if (!logon) {
252 return NT_STATUS_NO_MEMORY;
255 if (workstation) {
256 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
257 } else {
258 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
261 /* Initialise input parameters */
263 netlogon_creds_client_step(cli->dc, &clnt_creds);
265 switch (logon_type) {
266 case INTERACTIVE_LOGON_TYPE: {
268 struct netr_PasswordInfo *password_info;
270 struct samr_Password lmpassword;
271 struct samr_Password ntpassword;
273 unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16];
275 unsigned char lm_owf[16];
276 unsigned char nt_owf[16];
277 unsigned char key[16];
279 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
280 if (!password_info) {
281 return NT_STATUS_NO_MEMORY;
284 nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd);
286 #ifdef DEBUG_PASSWORD
287 DEBUG(100,("lm cypher:"));
288 dump_data(100, lm_owf_user_pwd, 16);
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);
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);
301 #ifdef DEBUG_PASSWORD
302 DEBUG(100,("encrypt of lm owf password:"));
303 dump_data(100, lm_owf, 16);
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);
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);
321 logon->password = password_info;
323 break;
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;
333 ZERO_STRUCT(lm);
334 ZERO_STRUCT(nt);
336 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
337 if (!network_info) {
338 return NT_STATUS_NO_MEMORY;
341 generate_random_buffer(chal, 8);
343 SMBencrypt(password, chal, local_lm_response);
344 SMBNTencrypt(password, chal, local_nt_response);
346 lm.length = 24;
347 lm.data = local_lm_response;
349 nt.length = 24;
350 nt.data = local_nt_response;
352 init_netr_NetworkInfo(network_info,
353 domain,
354 logon_parameters,
355 0xdead,
356 0xbeef,
357 username,
358 clnt_name_slash,
359 chal,
361 lm);
363 logon->network = network_info;
365 break;
367 default:
368 DEBUG(0, ("switch value %d not supported\n",
369 logon_type));
370 return NT_STATUS_INVALID_INFO_CLASS;
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);
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;
392 return result;
397 * Logon domain user with an 'network' SAM logon
399 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
402 NTSTATUS 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)
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;
428 *info3 = NULL;
430 ZERO_STRUCT(zeros);
431 ZERO_STRUCT(ret_creds);
433 ZERO_STRUCT(lm);
434 ZERO_STRUCT(nt);
436 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
437 if (!logon) {
438 return NT_STATUS_NO_MEMORY;
441 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
442 if (!network_info) {
443 return NT_STATUS_NO_MEMORY;
446 netlogon_creds_client_step(cli->dc, &clnt_creds);
448 if (server[0] != '\\' && server[1] != '\\') {
449 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
450 } else {
451 server_name_slash = server;
454 if (workstation[0] != '\\' && workstation[1] != '\\') {
455 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
456 } else {
457 workstation_name_slash = workstation;
460 if (!workstation_name_slash || !server_name_slash) {
461 DEBUG(0, ("talloc_asprintf failed!\n"));
462 return NT_STATUS_NO_MEMORY;
465 /* Initialise input parameters */
467 lm.data = lm_response.data;
468 lm.length = lm_response.length;
469 nt.data = nt_response.data;
470 nt.length = nt_response.length;
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,
481 lm);
483 logon->network = network_info;
485 /* Marshall data and send request */
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;
501 if (memcmp(zeros, validation.sam3->base.key.key, 16) != 0) {
502 SamOEMhash(validation.sam3->base.key.key,
503 cli->dc->sess_key, 16);
506 if (memcmp(zeros, validation.sam3->base.LMSessKey.key, 8) != 0) {
507 SamOEMhash(validation.sam3->base.LMSessKey.key,
508 cli->dc->sess_key, 8);
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;
519 *info3 = validation.sam3;
521 return result;
524 NTSTATUS 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)
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;
549 *info3 = NULL;
551 ZERO_STRUCT(zeros);
553 ZERO_STRUCT(lm);
554 ZERO_STRUCT(nt);
556 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
557 if (!logon) {
558 return NT_STATUS_NO_MEMORY;
561 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
562 if (!network_info) {
563 return NT_STATUS_NO_MEMORY;
566 if (server[0] != '\\' && server[1] != '\\') {
567 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
568 } else {
569 server_name_slash = server;
572 if (workstation[0] != '\\' && workstation[1] != '\\') {
573 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
574 } else {
575 workstation_name_slash = workstation;
578 if (!workstation_name_slash || !server_name_slash) {
579 DEBUG(0, ("talloc_asprintf failed!\n"));
580 return NT_STATUS_NO_MEMORY;
583 /* Initialise input parameters */
585 lm.data = lm_response.data;
586 lm.length = lm_response.length;
587 nt.data = nt_response.data;
588 nt.length = nt_response.length;
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,
599 lm);
601 logon->network = network_info;
603 /* Marshall data and send request */
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;
618 if (memcmp(zeros, validation.sam3->base.key.key, 16) != 0) {
619 SamOEMhash(validation.sam3->base.key.key,
620 cli->dc->sess_key, 16);
623 if (memcmp(zeros, validation.sam3->base.LMSessKey.key, 8) != 0) {
624 SamOEMhash(validation.sam3->base.LMSessKey.key,
625 cli->dc->sess_key, 8);
628 *info3 = validation.sam3;
630 return result;