s3:auth: add comment to nulling out stolen sampass
[Samba/fernandojvsilva.git] / source3 / rpc_client / cli_netlogon.c
blobe484209cbe3d7b0b83b8e0a6390a712c382adc8e
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"
25 #include "../librpc/gen_ndr/cli_netlogon.h"
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 ****************************************************************************/
33 NTSTATUS 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)
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;
49 if (!ndr_syntax_id_equal(&cli->abstract_syntax,
50 &ndr_table_netlogon.syntax_id)) {
51 return NT_STATUS_INVALID_PARAMETER;
54 TALLOC_FREE(cli->dc);
56 /* Store the machine account password we're going to use. */
57 memcpy(password.hash, machine_pwd, 16);
59 fstr_sprintf( mach_acct, "%s$", machine_account);
61 again:
62 /* Create the client challenge. */
63 generate_random_buffer(clnt_chal_send.data, 8);
65 /* Get the server challenge. */
66 result = rpccli_netr_ServerReqChallenge(cli, talloc_tos(),
67 cli->srv_name_slash,
68 clnt_name,
69 &clnt_chal_send,
70 &srv_chal_recv);
71 if (!NT_STATUS_IS_OK(result)) {
72 return result;
75 /* Calculate the session key and client credentials */
77 cli->dc = netlogon_creds_client_init(cli,
78 mach_acct,
79 clnt_name,
80 &clnt_chal_send,
81 &srv_chal_recv,
82 &password,
83 &clnt_chal_send,
84 *neg_flags_inout);
86 if (!cli->dc) {
87 return NT_STATUS_NO_MEMORY;
91 * Send client auth-2 challenge and receive server repy.
94 result = rpccli_netr_ServerAuthenticate2(cli, talloc_tos(),
95 cli->srv_name_slash,
96 cli->dc->account_name,
97 sec_chan_type,
98 cli->dc->computer_name,
99 &clnt_chal_send, /* input. */
100 &srv_chal_recv, /* output. */
101 neg_flags_inout);
103 /* we might be talking to NT4, so let's downgrade in that case and retry
104 * with the returned neg_flags - gd */
106 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
107 retried = true;
108 TALLOC_FREE(cli->dc);
109 goto again;
112 if (!NT_STATUS_IS_OK(result)) {
113 return result;
117 * Check the returned value using the initial
118 * server received challenge.
121 if (!netlogon_creds_client_check(cli->dc, &srv_chal_recv)) {
123 * Server replied with bad credential. Fail.
125 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
126 "replied with bad credential\n",
127 cli->desthost ));
128 return NT_STATUS_ACCESS_DENIED;
131 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
132 "chain established.\n",
133 cli->desthost ));
135 return NT_STATUS_OK;
138 /* Logon domain user */
140 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
141 TALLOC_CTX *mem_ctx,
142 uint32 logon_parameters,
143 const char *domain,
144 const char *username,
145 const char *password,
146 const char *workstation,
147 int logon_type)
149 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
150 struct netr_Authenticator clnt_creds;
151 struct netr_Authenticator ret_creds;
152 union netr_LogonLevel *logon;
153 union netr_Validation validation;
154 uint8_t authoritative;
155 int validation_level = 3;
156 fstring clnt_name_slash;
158 ZERO_STRUCT(ret_creds);
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_authenticator(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 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
184 if (!password_info) {
185 return NT_STATUS_NO_MEMORY;
188 nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash);
190 if (cli->dc->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
191 netlogon_creds_arcfour_crypt(cli->dc, lmpassword.hash, 16);
192 netlogon_creds_arcfour_crypt(cli->dc, ntpassword.hash, 16);
193 } else {
194 netlogon_creds_des_encrypt(cli->dc, &lmpassword);
195 netlogon_creds_des_encrypt(cli->dc, &ntpassword);
198 password_info->identity_info.domain_name.string = domain;
199 password_info->identity_info.parameter_control = logon_parameters;
200 password_info->identity_info.logon_id_low = 0xdead;
201 password_info->identity_info.logon_id_high = 0xbeef;
202 password_info->identity_info.account_name.string = username;
203 password_info->identity_info.workstation.string = clnt_name_slash;
205 password_info->lmpassword = lmpassword;
206 password_info->ntpassword = ntpassword;
208 logon->password = password_info;
210 break;
212 case NetlogonNetworkInformation: {
213 struct netr_NetworkInfo *network_info;
214 uint8 chal[8];
215 unsigned char local_lm_response[24];
216 unsigned char local_nt_response[24];
217 struct netr_ChallengeResponse lm;
218 struct netr_ChallengeResponse nt;
220 ZERO_STRUCT(lm);
221 ZERO_STRUCT(nt);
223 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
224 if (!network_info) {
225 return NT_STATUS_NO_MEMORY;
228 generate_random_buffer(chal, 8);
230 SMBencrypt(password, chal, local_lm_response);
231 SMBNTencrypt(password, chal, local_nt_response);
233 lm.length = 24;
234 lm.data = local_lm_response;
236 nt.length = 24;
237 nt.data = local_nt_response;
239 network_info->identity_info.domain_name.string = domain;
240 network_info->identity_info.parameter_control = logon_parameters;
241 network_info->identity_info.logon_id_low = 0xdead;
242 network_info->identity_info.logon_id_high = 0xbeef;
243 network_info->identity_info.account_name.string = username;
244 network_info->identity_info.workstation.string = clnt_name_slash;
246 memcpy(network_info->challenge, chal, 8);
247 network_info->nt = nt;
248 network_info->lm = lm;
250 logon->network = network_info;
252 break;
254 default:
255 DEBUG(0, ("switch value %d not supported\n",
256 logon_type));
257 return NT_STATUS_INVALID_INFO_CLASS;
260 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
261 cli->srv_name_slash,
262 global_myname(),
263 &clnt_creds,
264 &ret_creds,
265 logon_type,
266 logon,
267 validation_level,
268 &validation,
269 &authoritative);
271 /* Always check returned credentials */
272 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
273 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
274 return NT_STATUS_ACCESS_DENIED;
277 return result;
282 * Logon domain user with an 'network' SAM logon
284 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
287 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
288 TALLOC_CTX *mem_ctx,
289 uint32 logon_parameters,
290 const char *server,
291 const char *username,
292 const char *domain,
293 const char *workstation,
294 const uint8 chal[8],
295 DATA_BLOB lm_response,
296 DATA_BLOB nt_response,
297 struct netr_SamInfo3 **info3)
299 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
300 int validation_level = 3;
301 const char *workstation_name_slash;
302 const char *server_name_slash;
303 struct netr_Authenticator clnt_creds;
304 struct netr_Authenticator ret_creds;
305 union netr_LogonLevel *logon = NULL;
306 struct netr_NetworkInfo *network_info;
307 uint8_t authoritative;
308 union netr_Validation validation;
309 struct netr_ChallengeResponse lm;
310 struct netr_ChallengeResponse nt;
312 *info3 = NULL;
314 ZERO_STRUCT(ret_creds);
316 ZERO_STRUCT(lm);
317 ZERO_STRUCT(nt);
319 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
320 if (!logon) {
321 return NT_STATUS_NO_MEMORY;
324 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
325 if (!network_info) {
326 return NT_STATUS_NO_MEMORY;
329 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
331 if (server[0] != '\\' && server[1] != '\\') {
332 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
333 } else {
334 server_name_slash = server;
337 if (workstation[0] != '\\' && workstation[1] != '\\') {
338 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
339 } else {
340 workstation_name_slash = workstation;
343 if (!workstation_name_slash || !server_name_slash) {
344 DEBUG(0, ("talloc_asprintf failed!\n"));
345 return NT_STATUS_NO_MEMORY;
348 /* Initialise input parameters */
350 lm.data = lm_response.data;
351 lm.length = lm_response.length;
352 nt.data = nt_response.data;
353 nt.length = nt_response.length;
355 network_info->identity_info.domain_name.string = domain;
356 network_info->identity_info.parameter_control = logon_parameters;
357 network_info->identity_info.logon_id_low = 0xdead;
358 network_info->identity_info.logon_id_high = 0xbeef;
359 network_info->identity_info.account_name.string = username;
360 network_info->identity_info.workstation.string = workstation_name_slash;
362 memcpy(network_info->challenge, chal, 8);
363 network_info->nt = nt;
364 network_info->lm = lm;
366 logon->network = network_info;
368 /* Marshall data and send request */
370 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
371 server_name_slash,
372 global_myname(),
373 &clnt_creds,
374 &ret_creds,
375 NetlogonNetworkInformation,
376 logon,
377 validation_level,
378 &validation,
379 &authoritative);
380 if (!NT_STATUS_IS_OK(result)) {
381 return result;
384 /* Always check returned credentials. */
385 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
386 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
387 return NT_STATUS_ACCESS_DENIED;
390 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
392 *info3 = validation.sam3;
394 return result;
397 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
398 TALLOC_CTX *mem_ctx,
399 uint32 logon_parameters,
400 const char *server,
401 const char *username,
402 const char *domain,
403 const char *workstation,
404 const uint8 chal[8],
405 DATA_BLOB lm_response,
406 DATA_BLOB nt_response,
407 struct netr_SamInfo3 **info3)
409 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
410 int validation_level = 3;
411 const char *workstation_name_slash;
412 const char *server_name_slash;
413 union netr_LogonLevel *logon = NULL;
414 struct netr_NetworkInfo *network_info;
415 uint8_t authoritative;
416 union netr_Validation validation;
417 struct netr_ChallengeResponse lm;
418 struct netr_ChallengeResponse nt;
419 uint32_t flags = 0;
421 *info3 = NULL;
423 ZERO_STRUCT(lm);
424 ZERO_STRUCT(nt);
426 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
427 if (!logon) {
428 return NT_STATUS_NO_MEMORY;
431 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
432 if (!network_info) {
433 return NT_STATUS_NO_MEMORY;
436 if (server[0] != '\\' && server[1] != '\\') {
437 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
438 } else {
439 server_name_slash = server;
442 if (workstation[0] != '\\' && workstation[1] != '\\') {
443 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
444 } else {
445 workstation_name_slash = workstation;
448 if (!workstation_name_slash || !server_name_slash) {
449 DEBUG(0, ("talloc_asprintf failed!\n"));
450 return NT_STATUS_NO_MEMORY;
453 /* Initialise input parameters */
455 lm.data = lm_response.data;
456 lm.length = lm_response.length;
457 nt.data = nt_response.data;
458 nt.length = nt_response.length;
460 network_info->identity_info.domain_name.string = domain;
461 network_info->identity_info.parameter_control = logon_parameters;
462 network_info->identity_info.logon_id_low = 0xdead;
463 network_info->identity_info.logon_id_high = 0xbeef;
464 network_info->identity_info.account_name.string = username;
465 network_info->identity_info.workstation.string = workstation_name_slash;
467 memcpy(network_info->challenge, chal, 8);
468 network_info->nt = nt;
469 network_info->lm = lm;
471 logon->network = network_info;
473 /* Marshall data and send request */
475 result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
476 server_name_slash,
477 global_myname(),
478 NetlogonNetworkInformation,
479 logon,
480 validation_level,
481 &validation,
482 &authoritative,
483 &flags);
484 if (!NT_STATUS_IS_OK(result)) {
485 return result;
488 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
490 *info3 = validation.sam3;
492 return result;
495 /*********************************************************
496 Change the domain password on the PDC.
498 Just changes the password betwen the two values specified.
500 Caller must have the cli connected to the netlogon pipe
501 already.
502 **********************************************************/
504 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
505 TALLOC_CTX *mem_ctx,
506 const char *account_name,
507 const unsigned char orig_trust_passwd_hash[16],
508 const char *new_trust_pwd_cleartext,
509 const unsigned char new_trust_passwd_hash[16],
510 enum netr_SchannelType sec_channel_type)
512 NTSTATUS result;
513 struct netr_Authenticator clnt_creds, srv_cred;
515 if (!cli->dc) {
516 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
517 result = rpccli_netlogon_setup_creds(cli,
518 cli->desthost, /* server name */
519 lp_workgroup(), /* domain */
520 global_myname(), /* client name */
521 account_name, /* machine account name */
522 orig_trust_passwd_hash,
523 sec_channel_type,
524 &neg_flags);
525 if (!NT_STATUS_IS_OK(result)) {
526 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
527 nt_errstr(result)));
528 return result;
532 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
534 if (cli->dc->negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
536 struct netr_CryptPassword new_password;
538 init_netr_CryptPassword(new_trust_pwd_cleartext,
539 cli->dc->session_key,
540 &new_password);
542 result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx,
543 cli->srv_name_slash,
544 cli->dc->account_name,
545 sec_channel_type,
546 cli->dc->computer_name,
547 &clnt_creds,
548 &srv_cred,
549 &new_password);
550 if (!NT_STATUS_IS_OK(result)) {
551 DEBUG(0,("rpccli_netr_ServerPasswordSet2 failed: %s\n",
552 nt_errstr(result)));
553 return result;
555 } else {
557 struct samr_Password new_password;
558 memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash));
559 netlogon_creds_des_encrypt(cli->dc, &new_password);
561 result = rpccli_netr_ServerPasswordSet(cli, mem_ctx,
562 cli->srv_name_slash,
563 cli->dc->account_name,
564 sec_channel_type,
565 cli->dc->computer_name,
566 &clnt_creds,
567 &srv_cred,
568 &new_password);
569 if (!NT_STATUS_IS_OK(result)) {
570 DEBUG(0,("rpccli_netr_ServerPasswordSet failed: %s\n",
571 nt_errstr(result)));
572 return result;
576 /* Always check returned credentials. */
577 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
578 DEBUG(0,("credentials chain check failed\n"));
579 return NT_STATUS_ACCESS_DENIED;
582 return result;