Rework Samba3 to use new libcli/auth code (partial)
[Samba/gbeck.git] / source3 / rpc_client / cli_netlogon.c
blob00d7f8515be86412690474cbe103f57730c9ecce
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"
26 /****************************************************************************
27 Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
28 credentials chain. Stores the credentials in the struct dcinfo in the
29 netlogon pipe struct.
30 ****************************************************************************/
32 NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
33 const char *server_name,
34 const char *domain,
35 const char *clnt_name,
36 const char *machine_account,
37 const unsigned char machine_pwd[16],
38 enum netr_SchannelType sec_chan_type,
39 uint32_t *neg_flags_inout)
41 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
42 struct netr_Credential clnt_chal_send;
43 struct netr_Credential srv_chal_recv;
44 struct netr_Credentials *dc;
45 bool retried = false;
47 SMB_ASSERT(ndr_syntax_id_equal(&cli->abstract_syntax,
48 &ndr_table_netlogon.syntax_id));
50 TALLOC_FREE(cli->dc);
51 cli->dc = talloc_zero(cli, struct dcinfo);
52 if (cli->dc == NULL) {
53 return NT_STATUS_NO_MEMORY;
55 dc = cli->dc;
57 /* Store the machine account password we're going to use. */
58 memcpy(dc->mach_pw, machine_pwd, 16);
60 fstrcpy(dc->remote_machine, "\\\\");
61 fstrcat(dc->remote_machine, server_name);
63 fstrcpy(dc->domain, domain);
65 fstr_sprintf( dc->mach_acct, "%s$", machine_account);
67 again:
68 /* Create the client challenge. */
69 generate_random_buffer(clnt_chal_send.data, 8);
71 /* Get the server challenge. */
72 result = rpccli_netr_ServerReqChallenge(cli, talloc_tos(),
73 dc->remote_machine,
74 clnt_name,
75 &clnt_chal_send,
76 &srv_chal_recv);
77 if (!NT_STATUS_IS_OK(result)) {
78 return result;
81 /* Calculate the session key and client credentials */
82 creds_client_init(*neg_flags_inout,
83 dc,
84 &clnt_chal_send,
85 &srv_chal_recv,
86 machine_pwd,
87 &clnt_chal_send);
90 * Send client auth-2 challenge and receive server repy.
93 result = rpccli_netr_ServerAuthenticate2(cli, talloc_tos(),
94 dc->remote_machine,
95 dc->mach_acct,
96 sec_chan_type,
97 clnt_name,
98 &clnt_chal_send, /* input. */
99 &srv_chal_recv, /* output. */
100 neg_flags_inout);
102 /* we might be talking to NT4, so let's downgrade in that case and retry
103 * with the returned neg_flags - gd */
105 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
106 retried = true;
107 goto again;
110 if (!NT_STATUS_IS_OK(result)) {
111 return result;
115 * Check the returned value using the initial
116 * server received challenge.
119 if (!netlogon_creds_client_check(dc, &srv_chal_recv)) {
121 * Server replied with bad credential. Fail.
123 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
124 "replied with bad credential\n",
125 cli->desthost ));
126 return NT_STATUS_ACCESS_DENIED;
129 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
130 "chain established.\n",
131 cli->desthost ));
133 return NT_STATUS_OK;
136 /* Logon domain user */
138 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
139 TALLOC_CTX *mem_ctx,
140 uint32 logon_parameters,
141 const char *domain,
142 const char *username,
143 const char *password,
144 const char *workstation,
145 int logon_type)
147 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
148 struct netr_Authenticator clnt_creds;
149 struct netr_Authenticator ret_creds;
150 union netr_LogonLevel *logon;
151 union netr_Validation validation;
152 uint8_t authoritative;
153 int validation_level = 3;
154 fstring clnt_name_slash;
155 uint8 zeros[16];
157 ZERO_STRUCT(ret_creds);
158 ZERO_STRUCT(zeros);
160 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
161 if (!logon) {
162 return NT_STATUS_NO_MEMORY;
165 if (workstation) {
166 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
167 } else {
168 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
171 /* Initialise input parameters */
173 netlogon_creds_client_step(cli->dc, &clnt_creds);
175 switch (logon_type) {
176 case NetlogonInteractiveInformation: {
178 struct netr_PasswordInfo *password_info;
180 struct samr_Password lmpassword;
181 struct samr_Password ntpassword;
183 unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16];
185 unsigned char lm_owf[16];
186 unsigned char nt_owf[16];
187 unsigned char key[16];
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, nt_owf_user_pwd, lm_owf_user_pwd);
196 #ifdef DEBUG_PASSWORD
197 DEBUG(100,("lm cypher:"));
198 dump_data(100, lm_owf_user_pwd, 16);
200 DEBUG(100,("nt cypher:"));
201 dump_data(100, nt_owf_user_pwd, 16);
202 #endif
203 memset(key, 0, 16);
204 memcpy(key, cli->dc->sess_key, 8);
206 memcpy(lm_owf, lm_owf_user_pwd, 16);
207 arcfour_crypt(lm_owf, key, 16);
208 memcpy(nt_owf, nt_owf_user_pwd, 16);
209 arcfour_crypt(nt_owf, key, 16);
211 #ifdef DEBUG_PASSWORD
212 DEBUG(100,("encrypt of lm owf password:"));
213 dump_data(100, lm_owf, 16);
215 DEBUG(100,("encrypt of nt owf password:"));
216 dump_data(100, nt_owf, 16);
217 #endif
218 memcpy(lmpassword.hash, lm_owf, 16);
219 memcpy(ntpassword.hash, nt_owf, 16);
221 init_netr_PasswordInfo(password_info,
222 domain,
223 logon_parameters,
224 0xdead,
225 0xbeef,
226 username,
227 clnt_name_slash,
228 lmpassword,
229 ntpassword);
231 logon->password = password_info;
233 break;
235 case NetlogonNetworkInformation: {
236 struct netr_NetworkInfo *network_info;
237 uint8 chal[8];
238 unsigned char local_lm_response[24];
239 unsigned char local_nt_response[24];
240 struct netr_ChallengeResponse lm;
241 struct netr_ChallengeResponse nt;
243 ZERO_STRUCT(lm);
244 ZERO_STRUCT(nt);
246 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
247 if (!network_info) {
248 return NT_STATUS_NO_MEMORY;
251 generate_random_buffer(chal, 8);
253 SMBencrypt(password, chal, local_lm_response);
254 SMBNTencrypt(password, chal, local_nt_response);
256 lm.length = 24;
257 lm.data = local_lm_response;
259 nt.length = 24;
260 nt.data = local_nt_response;
262 init_netr_NetworkInfo(network_info,
263 domain,
264 logon_parameters,
265 0xdead,
266 0xbeef,
267 username,
268 clnt_name_slash,
269 chal,
271 lm);
273 logon->network = network_info;
275 break;
277 default:
278 DEBUG(0, ("switch value %d not supported\n",
279 logon_type));
280 return NT_STATUS_INVALID_INFO_CLASS;
283 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
284 cli->dc->remote_machine,
285 global_myname(),
286 &clnt_creds,
287 &ret_creds,
288 logon_type,
289 logon,
290 validation_level,
291 &validation,
292 &authoritative);
294 if (memcmp(zeros, &ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
295 /* Check returned credentials if present. */
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;
302 return result;
307 * Logon domain user with an 'network' SAM logon
309 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
312 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
313 TALLOC_CTX *mem_ctx,
314 uint32 logon_parameters,
315 const char *server,
316 const char *username,
317 const char *domain,
318 const char *workstation,
319 const uint8 chal[8],
320 DATA_BLOB lm_response,
321 DATA_BLOB nt_response,
322 struct netr_SamInfo3 **info3)
324 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
325 int validation_level = 3;
326 const char *workstation_name_slash;
327 const char *server_name_slash;
328 uint8 zeros[16];
329 struct netr_Authenticator clnt_creds;
330 struct netr_Authenticator ret_creds;
331 union netr_LogonLevel *logon = NULL;
332 struct netr_NetworkInfo *network_info;
333 uint8_t authoritative;
334 union netr_Validation validation;
335 struct netr_ChallengeResponse lm;
336 struct netr_ChallengeResponse nt;
338 *info3 = NULL;
340 ZERO_STRUCT(zeros);
341 ZERO_STRUCT(ret_creds);
343 ZERO_STRUCT(lm);
344 ZERO_STRUCT(nt);
346 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
347 if (!logon) {
348 return NT_STATUS_NO_MEMORY;
351 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
352 if (!network_info) {
353 return NT_STATUS_NO_MEMORY;
356 netlogon_creds_client_step(cli->dc, &clnt_creds);
358 if (server[0] != '\\' && server[1] != '\\') {
359 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
360 } else {
361 server_name_slash = server;
364 if (workstation[0] != '\\' && workstation[1] != '\\') {
365 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
366 } else {
367 workstation_name_slash = workstation;
370 if (!workstation_name_slash || !server_name_slash) {
371 DEBUG(0, ("talloc_asprintf failed!\n"));
372 return NT_STATUS_NO_MEMORY;
375 /* Initialise input parameters */
377 lm.data = lm_response.data;
378 lm.length = lm_response.length;
379 nt.data = nt_response.data;
380 nt.length = nt_response.length;
382 init_netr_NetworkInfo(network_info,
383 domain,
384 logon_parameters,
385 0xdead,
386 0xbeef,
387 username,
388 workstation_name_slash,
389 (uint8_t *) chal,
391 lm);
393 logon->network = network_info;
395 /* Marshall data and send request */
397 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
398 server_name_slash,
399 global_myname(),
400 &clnt_creds,
401 &ret_creds,
402 NetlogonNetworkInformation,
403 logon,
404 validation_level,
405 &validation,
406 &authoritative);
407 if (!NT_STATUS_IS_OK(result)) {
408 return result;
411 if (memcmp(zeros, validation.sam3->base.key.key, 16) != 0) {
412 arcfour_crypt(validation.sam3->base.key.key,
413 cli->dc->sess_key, 16);
416 if (memcmp(zeros, validation.sam3->base.LMSessKey.key, 8) != 0) {
417 arcfour_crypt(validation.sam3->base.LMSessKey.key,
418 cli->dc->sess_key, 8);
421 if (memcmp(zeros, ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
422 /* Check returned credentials if present. */
423 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
424 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
425 return NT_STATUS_ACCESS_DENIED;
429 *info3 = validation.sam3;
431 return result;
434 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
435 TALLOC_CTX *mem_ctx,
436 uint32 logon_parameters,
437 const char *server,
438 const char *username,
439 const char *domain,
440 const char *workstation,
441 const uint8 chal[8],
442 DATA_BLOB lm_response,
443 DATA_BLOB nt_response,
444 struct netr_SamInfo3 **info3)
446 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
447 int validation_level = 3;
448 const char *workstation_name_slash;
449 const char *server_name_slash;
450 uint8 zeros[16];
451 union netr_LogonLevel *logon = NULL;
452 struct netr_NetworkInfo *network_info;
453 uint8_t authoritative;
454 union netr_Validation validation;
455 struct netr_ChallengeResponse lm;
456 struct netr_ChallengeResponse nt;
457 uint32_t flags = 0;
459 *info3 = NULL;
461 ZERO_STRUCT(zeros);
463 ZERO_STRUCT(lm);
464 ZERO_STRUCT(nt);
466 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
467 if (!logon) {
468 return NT_STATUS_NO_MEMORY;
471 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
472 if (!network_info) {
473 return NT_STATUS_NO_MEMORY;
476 if (server[0] != '\\' && server[1] != '\\') {
477 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
478 } else {
479 server_name_slash = server;
482 if (workstation[0] != '\\' && workstation[1] != '\\') {
483 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
484 } else {
485 workstation_name_slash = workstation;
488 if (!workstation_name_slash || !server_name_slash) {
489 DEBUG(0, ("talloc_asprintf failed!\n"));
490 return NT_STATUS_NO_MEMORY;
493 /* Initialise input parameters */
495 lm.data = lm_response.data;
496 lm.length = lm_response.length;
497 nt.data = nt_response.data;
498 nt.length = nt_response.length;
500 init_netr_NetworkInfo(network_info,
501 domain,
502 logon_parameters,
503 0xdead,
504 0xbeef,
505 username,
506 workstation_name_slash,
507 (uint8_t *) chal,
509 lm);
511 logon->network = network_info;
513 /* Marshall data and send request */
515 result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
516 server_name_slash,
517 global_myname(),
518 NetlogonNetworkInformation,
519 logon,
520 validation_level,
521 &validation,
522 &authoritative,
523 &flags);
524 if (!NT_STATUS_IS_OK(result)) {
525 return result;
528 if (memcmp(zeros, validation.sam3->base.key.key, 16) != 0) {
529 arcfour_crypt(validation.sam3->base.key.key,
530 cli->dc->sess_key, 16);
533 if (memcmp(zeros, validation.sam3->base.LMSessKey.key, 8) != 0) {
534 arcfour_crypt(validation.sam3->base.LMSessKey.key,
535 cli->dc->sess_key, 8);
538 *info3 = validation.sam3;
540 return result;
543 /*********************************************************
544 Change the domain password on the PDC.
546 Just changes the password betwen the two values specified.
548 Caller must have the cli connected to the netlogon pipe
549 already.
550 **********************************************************/
552 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
553 TALLOC_CTX *mem_ctx,
554 const unsigned char orig_trust_passwd_hash[16],
555 const char *new_trust_pwd_cleartext,
556 const unsigned char new_trust_passwd_hash[16],
557 uint32_t sec_channel_type)
559 NTSTATUS result;
560 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
561 struct netr_Authenticator clnt_creds, srv_cred;
563 result = rpccli_netlogon_setup_creds(cli,
564 cli->desthost, /* server name */
565 lp_workgroup(), /* domain */
566 global_myname(), /* client name */
567 global_myname(), /* machine account name */
568 orig_trust_passwd_hash,
569 sec_channel_type,
570 &neg_flags);
572 if (!NT_STATUS_IS_OK(result)) {
573 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
574 nt_errstr(result)));
575 return result;
578 netlogon_creds_client_step(cli->dc, &clnt_creds);
580 if (neg_flags & NETLOGON_NEG_PASSWORD_SET2) {
582 struct netr_CryptPassword new_password;
584 init_netr_CryptPassword(new_trust_pwd_cleartext,
585 cli->dc->sess_key,
586 &new_password);
588 result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx,
589 cli->dc->remote_machine,
590 cli->dc->mach_acct,
591 sec_channel_type,
592 global_myname(),
593 &clnt_creds,
594 &srv_cred,
595 &new_password);
596 if (!NT_STATUS_IS_OK(result)) {
597 DEBUG(0,("rpccli_netr_ServerPasswordSet2 failed: %s\n",
598 nt_errstr(result)));
599 return result;
601 } else {
603 struct samr_Password new_password;
605 cred_hash3(new_password.hash,
606 new_trust_passwd_hash,
607 cli->dc->sess_key, 1);
609 result = rpccli_netr_ServerPasswordSet(cli, mem_ctx,
610 cli->dc->remote_machine,
611 cli->dc->mach_acct,
612 sec_channel_type,
613 global_myname(),
614 &clnt_creds,
615 &srv_cred,
616 &new_password);
617 if (!NT_STATUS_IS_OK(result)) {
618 DEBUG(0,("rpccli_netr_ServerPasswordSet failed: %s\n",
619 nt_errstr(result)));
620 return result;
624 /* Always check returned credentials. */
625 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
626 DEBUG(0,("credentials chain check failed\n"));
627 return NT_STATUS_ACCESS_DENIED;
630 return result;