s4-ldb: cope better with corruption of tdb records
[Samba/aatanasov.git] / source3 / rpc_client / cli_netlogon.c
blob911a50f39327483647a398dacc87949c52ab21e7
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 samr_Password password;
45 bool retried = false;
46 fstring mach_acct;
48 if (!ndr_syntax_id_equal(&cli->abstract_syntax,
49 &ndr_table_netlogon.syntax_id)) {
50 return NT_STATUS_INVALID_PARAMETER;
53 TALLOC_FREE(cli->dc);
55 /* Store the machine account password we're going to use. */
56 memcpy(password.hash, machine_pwd, 16);
58 fstr_sprintf( mach_acct, "%s$", machine_account);
60 again:
61 /* Create the client challenge. */
62 generate_random_buffer(clnt_chal_send.data, 8);
64 /* Get the server challenge. */
65 result = rpccli_netr_ServerReqChallenge(cli, talloc_tos(),
66 cli->srv_name_slash,
67 clnt_name,
68 &clnt_chal_send,
69 &srv_chal_recv);
70 if (!NT_STATUS_IS_OK(result)) {
71 return result;
74 /* Calculate the session key and client credentials */
76 cli->dc = netlogon_creds_client_init(cli,
77 mach_acct,
78 clnt_name,
79 &clnt_chal_send,
80 &srv_chal_recv,
81 &password,
82 &clnt_chal_send,
83 *neg_flags_inout);
85 if (!cli->dc) {
86 return NT_STATUS_NO_MEMORY;
90 * Send client auth-2 challenge and receive server repy.
93 result = rpccli_netr_ServerAuthenticate2(cli, talloc_tos(),
94 cli->srv_name_slash,
95 cli->dc->account_name,
96 sec_chan_type,
97 cli->dc->computer_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 TALLOC_FREE(cli->dc);
108 goto again;
111 if (!NT_STATUS_IS_OK(result)) {
112 return result;
116 * Check the returned value using the initial
117 * server received challenge.
120 if (!netlogon_creds_client_check(cli->dc, &srv_chal_recv)) {
122 * Server replied with bad credential. Fail.
124 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
125 "replied with bad credential\n",
126 cli->desthost ));
127 return NT_STATUS_ACCESS_DENIED;
130 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
131 "chain established.\n",
132 cli->desthost ));
134 return NT_STATUS_OK;
137 /* Logon domain user */
139 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
140 TALLOC_CTX *mem_ctx,
141 uint32 logon_parameters,
142 const char *domain,
143 const char *username,
144 const char *password,
145 const char *workstation,
146 int logon_type)
148 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
149 struct netr_Authenticator clnt_creds;
150 struct netr_Authenticator ret_creds;
151 union netr_LogonLevel *logon;
152 union netr_Validation validation;
153 uint8_t authoritative;
154 int validation_level = 3;
155 fstring clnt_name_slash;
156 uint8 zeros[16];
158 ZERO_STRUCT(ret_creds);
159 ZERO_STRUCT(zeros);
161 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
162 if (!logon) {
163 return NT_STATUS_NO_MEMORY;
166 if (workstation) {
167 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
168 } else {
169 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
172 /* Initialise input parameters */
174 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
176 switch (logon_type) {
177 case NetlogonInteractiveInformation: {
179 struct netr_PasswordInfo *password_info;
181 struct samr_Password lmpassword;
182 struct samr_Password ntpassword;
184 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
185 if (!password_info) {
186 return NT_STATUS_NO_MEMORY;
189 nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash);
191 if (cli->dc->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
192 netlogon_creds_arcfour_crypt(cli->dc, lmpassword.hash, 16);
193 netlogon_creds_arcfour_crypt(cli->dc, ntpassword.hash, 16);
194 } else {
195 netlogon_creds_des_encrypt(cli->dc, &lmpassword);
196 netlogon_creds_des_encrypt(cli->dc, &ntpassword);
199 password_info->identity_info.domain_name.string = domain;
200 password_info->identity_info.parameter_control = logon_parameters;
201 password_info->identity_info.logon_id_low = 0xdead;
202 password_info->identity_info.logon_id_high = 0xbeef;
203 password_info->identity_info.account_name.string = username;
204 password_info->identity_info.workstation.string = clnt_name_slash;
206 password_info->lmpassword = lmpassword;
207 password_info->ntpassword = ntpassword;
209 logon->password = password_info;
211 break;
213 case NetlogonNetworkInformation: {
214 struct netr_NetworkInfo *network_info;
215 uint8 chal[8];
216 unsigned char local_lm_response[24];
217 unsigned char local_nt_response[24];
218 struct netr_ChallengeResponse lm;
219 struct netr_ChallengeResponse nt;
221 ZERO_STRUCT(lm);
222 ZERO_STRUCT(nt);
224 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
225 if (!network_info) {
226 return NT_STATUS_NO_MEMORY;
229 generate_random_buffer(chal, 8);
231 SMBencrypt(password, chal, local_lm_response);
232 SMBNTencrypt(password, chal, local_nt_response);
234 lm.length = 24;
235 lm.data = local_lm_response;
237 nt.length = 24;
238 nt.data = local_nt_response;
240 network_info->identity_info.domain_name.string = domain;
241 network_info->identity_info.parameter_control = logon_parameters;
242 network_info->identity_info.logon_id_low = 0xdead;
243 network_info->identity_info.logon_id_high = 0xbeef;
244 network_info->identity_info.account_name.string = username;
245 network_info->identity_info.workstation.string = clnt_name_slash;
247 memcpy(network_info->challenge, chal, 8);
248 network_info->nt = nt;
249 network_info->lm = lm;
251 logon->network = network_info;
253 break;
255 default:
256 DEBUG(0, ("switch value %d not supported\n",
257 logon_type));
258 return NT_STATUS_INVALID_INFO_CLASS;
261 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
262 cli->srv_name_slash,
263 global_myname(),
264 &clnt_creds,
265 &ret_creds,
266 logon_type,
267 logon,
268 validation_level,
269 &validation,
270 &authoritative);
272 /* Always check returned credentials */
273 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
274 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
275 return NT_STATUS_ACCESS_DENIED;
278 return result;
283 * Logon domain user with an 'network' SAM logon
285 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
288 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
289 TALLOC_CTX *mem_ctx,
290 uint32 logon_parameters,
291 const char *server,
292 const char *username,
293 const char *domain,
294 const char *workstation,
295 const uint8 chal[8],
296 DATA_BLOB lm_response,
297 DATA_BLOB nt_response,
298 struct netr_SamInfo3 **info3)
300 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
301 int validation_level = 3;
302 const char *workstation_name_slash;
303 const char *server_name_slash;
304 uint8 zeros[16];
305 struct netr_Authenticator clnt_creds;
306 struct netr_Authenticator ret_creds;
307 union netr_LogonLevel *logon = NULL;
308 struct netr_NetworkInfo *network_info;
309 uint8_t authoritative;
310 union netr_Validation validation;
311 struct netr_ChallengeResponse lm;
312 struct netr_ChallengeResponse nt;
314 *info3 = NULL;
316 ZERO_STRUCT(zeros);
317 ZERO_STRUCT(ret_creds);
319 ZERO_STRUCT(lm);
320 ZERO_STRUCT(nt);
322 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
323 if (!logon) {
324 return NT_STATUS_NO_MEMORY;
327 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
328 if (!network_info) {
329 return NT_STATUS_NO_MEMORY;
332 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
334 if (server[0] != '\\' && server[1] != '\\') {
335 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
336 } else {
337 server_name_slash = server;
340 if (workstation[0] != '\\' && workstation[1] != '\\') {
341 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
342 } else {
343 workstation_name_slash = workstation;
346 if (!workstation_name_slash || !server_name_slash) {
347 DEBUG(0, ("talloc_asprintf failed!\n"));
348 return NT_STATUS_NO_MEMORY;
351 /* Initialise input parameters */
353 lm.data = lm_response.data;
354 lm.length = lm_response.length;
355 nt.data = nt_response.data;
356 nt.length = nt_response.length;
358 network_info->identity_info.domain_name.string = domain;
359 network_info->identity_info.parameter_control = logon_parameters;
360 network_info->identity_info.logon_id_low = 0xdead;
361 network_info->identity_info.logon_id_high = 0xbeef;
362 network_info->identity_info.account_name.string = username;
363 network_info->identity_info.workstation.string = workstation_name_slash;
365 memcpy(network_info->challenge, chal, 8);
366 network_info->nt = nt;
367 network_info->lm = lm;
369 logon->network = network_info;
371 /* Marshall data and send request */
373 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
374 server_name_slash,
375 global_myname(),
376 &clnt_creds,
377 &ret_creds,
378 NetlogonNetworkInformation,
379 logon,
380 validation_level,
381 &validation,
382 &authoritative);
383 if (!NT_STATUS_IS_OK(result)) {
384 return result;
387 /* Always check returned credentials. */
388 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
389 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
390 return NT_STATUS_ACCESS_DENIED;
393 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
395 *info3 = validation.sam3;
397 return result;
400 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
401 TALLOC_CTX *mem_ctx,
402 uint32 logon_parameters,
403 const char *server,
404 const char *username,
405 const char *domain,
406 const char *workstation,
407 const uint8 chal[8],
408 DATA_BLOB lm_response,
409 DATA_BLOB nt_response,
410 struct netr_SamInfo3 **info3)
412 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
413 int validation_level = 3;
414 const char *workstation_name_slash;
415 const char *server_name_slash;
416 uint8 zeros[16];
417 union netr_LogonLevel *logon = NULL;
418 struct netr_NetworkInfo *network_info;
419 uint8_t authoritative;
420 union netr_Validation validation;
421 struct netr_ChallengeResponse lm;
422 struct netr_ChallengeResponse nt;
423 uint32_t flags = 0;
425 *info3 = NULL;
427 ZERO_STRUCT(zeros);
429 ZERO_STRUCT(lm);
430 ZERO_STRUCT(nt);
432 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
433 if (!logon) {
434 return NT_STATUS_NO_MEMORY;
437 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
438 if (!network_info) {
439 return NT_STATUS_NO_MEMORY;
442 if (server[0] != '\\' && server[1] != '\\') {
443 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
444 } else {
445 server_name_slash = server;
448 if (workstation[0] != '\\' && workstation[1] != '\\') {
449 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
450 } else {
451 workstation_name_slash = workstation;
454 if (!workstation_name_slash || !server_name_slash) {
455 DEBUG(0, ("talloc_asprintf failed!\n"));
456 return NT_STATUS_NO_MEMORY;
459 /* Initialise input parameters */
461 lm.data = lm_response.data;
462 lm.length = lm_response.length;
463 nt.data = nt_response.data;
464 nt.length = nt_response.length;
466 network_info->identity_info.domain_name.string = domain;
467 network_info->identity_info.parameter_control = logon_parameters;
468 network_info->identity_info.logon_id_low = 0xdead;
469 network_info->identity_info.logon_id_high = 0xbeef;
470 network_info->identity_info.account_name.string = username;
471 network_info->identity_info.workstation.string = workstation_name_slash;
473 memcpy(network_info->challenge, chal, 8);
474 network_info->nt = nt;
475 network_info->lm = lm;
477 logon->network = network_info;
479 /* Marshall data and send request */
481 result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
482 server_name_slash,
483 global_myname(),
484 NetlogonNetworkInformation,
485 logon,
486 validation_level,
487 &validation,
488 &authoritative,
489 &flags);
490 if (!NT_STATUS_IS_OK(result)) {
491 return result;
494 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
496 *info3 = validation.sam3;
498 return result;
501 /*********************************************************
502 Change the domain password on the PDC.
504 Just changes the password betwen the two values specified.
506 Caller must have the cli connected to the netlogon pipe
507 already.
508 **********************************************************/
510 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
511 TALLOC_CTX *mem_ctx,
512 const unsigned char orig_trust_passwd_hash[16],
513 const char *new_trust_pwd_cleartext,
514 const unsigned char new_trust_passwd_hash[16],
515 uint32_t sec_channel_type)
517 NTSTATUS result;
518 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
519 struct netr_Authenticator clnt_creds, srv_cred;
521 result = rpccli_netlogon_setup_creds(cli,
522 cli->desthost, /* server name */
523 lp_workgroup(), /* domain */
524 global_myname(), /* client name */
525 global_myname(), /* machine account name */
526 orig_trust_passwd_hash,
527 sec_channel_type,
528 &neg_flags);
530 if (!NT_STATUS_IS_OK(result)) {
531 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
532 nt_errstr(result)));
533 return result;
536 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
538 if (neg_flags & NETLOGON_NEG_PASSWORD_SET2) {
540 struct netr_CryptPassword new_password;
542 init_netr_CryptPassword(new_trust_pwd_cleartext,
543 cli->dc->session_key,
544 &new_password);
546 result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx,
547 cli->srv_name_slash,
548 cli->dc->account_name,
549 sec_channel_type,
550 cli->dc->computer_name,
551 &clnt_creds,
552 &srv_cred,
553 &new_password);
554 if (!NT_STATUS_IS_OK(result)) {
555 DEBUG(0,("rpccli_netr_ServerPasswordSet2 failed: %s\n",
556 nt_errstr(result)));
557 return result;
559 } else {
561 struct samr_Password new_password;
562 memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash));
563 netlogon_creds_des_encrypt(cli->dc, &new_password);
565 result = rpccli_netr_ServerPasswordSet(cli, mem_ctx,
566 cli->srv_name_slash,
567 cli->dc->account_name,
568 sec_channel_type,
569 cli->dc->computer_name,
570 &clnt_creds,
571 &srv_cred,
572 &new_password);
573 if (!NT_STATUS_IS_OK(result)) {
574 DEBUG(0,("rpccli_netr_ServerPasswordSet failed: %s\n",
575 nt_errstr(result)));
576 return result;
580 /* Always check returned credentials. */
581 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
582 DEBUG(0,("credentials chain check failed\n"));
583 return NT_STATUS_ACCESS_DENIED;
586 return result;