s3:docs: Document "aio write behind".
[Samba/gbeck.git] / source3 / rpc_client / cli_netlogon.c
blob03884479f9f08d77980030f7b2c2573ff1d5663a
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;
157 uint8 zeros[16];
159 ZERO_STRUCT(ret_creds);
160 ZERO_STRUCT(zeros);
162 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
163 if (!logon) {
164 return NT_STATUS_NO_MEMORY;
167 if (workstation) {
168 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
169 } else {
170 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
173 /* Initialise input parameters */
175 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
177 switch (logon_type) {
178 case NetlogonInteractiveInformation: {
180 struct netr_PasswordInfo *password_info;
182 struct samr_Password lmpassword;
183 struct samr_Password ntpassword;
185 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
186 if (!password_info) {
187 return NT_STATUS_NO_MEMORY;
190 nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash);
192 if (cli->dc->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
193 netlogon_creds_arcfour_crypt(cli->dc, lmpassword.hash, 16);
194 netlogon_creds_arcfour_crypt(cli->dc, ntpassword.hash, 16);
195 } else {
196 netlogon_creds_des_encrypt(cli->dc, &lmpassword);
197 netlogon_creds_des_encrypt(cli->dc, &ntpassword);
200 password_info->identity_info.domain_name.string = domain;
201 password_info->identity_info.parameter_control = logon_parameters;
202 password_info->identity_info.logon_id_low = 0xdead;
203 password_info->identity_info.logon_id_high = 0xbeef;
204 password_info->identity_info.account_name.string = username;
205 password_info->identity_info.workstation.string = clnt_name_slash;
207 password_info->lmpassword = lmpassword;
208 password_info->ntpassword = ntpassword;
210 logon->password = password_info;
212 break;
214 case NetlogonNetworkInformation: {
215 struct netr_NetworkInfo *network_info;
216 uint8 chal[8];
217 unsigned char local_lm_response[24];
218 unsigned char local_nt_response[24];
219 struct netr_ChallengeResponse lm;
220 struct netr_ChallengeResponse nt;
222 ZERO_STRUCT(lm);
223 ZERO_STRUCT(nt);
225 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
226 if (!network_info) {
227 return NT_STATUS_NO_MEMORY;
230 generate_random_buffer(chal, 8);
232 SMBencrypt(password, chal, local_lm_response);
233 SMBNTencrypt(password, chal, local_nt_response);
235 lm.length = 24;
236 lm.data = local_lm_response;
238 nt.length = 24;
239 nt.data = local_nt_response;
241 network_info->identity_info.domain_name.string = domain;
242 network_info->identity_info.parameter_control = logon_parameters;
243 network_info->identity_info.logon_id_low = 0xdead;
244 network_info->identity_info.logon_id_high = 0xbeef;
245 network_info->identity_info.account_name.string = username;
246 network_info->identity_info.workstation.string = clnt_name_slash;
248 memcpy(network_info->challenge, chal, 8);
249 network_info->nt = nt;
250 network_info->lm = lm;
252 logon->network = network_info;
254 break;
256 default:
257 DEBUG(0, ("switch value %d not supported\n",
258 logon_type));
259 return NT_STATUS_INVALID_INFO_CLASS;
262 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
263 cli->srv_name_slash,
264 global_myname(),
265 &clnt_creds,
266 &ret_creds,
267 logon_type,
268 logon,
269 validation_level,
270 &validation,
271 &authoritative);
273 /* Always check returned credentials */
274 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
275 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
276 return NT_STATUS_ACCESS_DENIED;
279 return result;
284 * Logon domain user with an 'network' SAM logon
286 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
289 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
290 TALLOC_CTX *mem_ctx,
291 uint32 logon_parameters,
292 const char *server,
293 const char *username,
294 const char *domain,
295 const char *workstation,
296 const uint8 chal[8],
297 DATA_BLOB lm_response,
298 DATA_BLOB nt_response,
299 struct netr_SamInfo3 **info3)
301 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
302 int validation_level = 3;
303 const char *workstation_name_slash;
304 const char *server_name_slash;
305 uint8 zeros[16];
306 struct netr_Authenticator clnt_creds;
307 struct netr_Authenticator ret_creds;
308 union netr_LogonLevel *logon = NULL;
309 struct netr_NetworkInfo *network_info;
310 uint8_t authoritative;
311 union netr_Validation validation;
312 struct netr_ChallengeResponse lm;
313 struct netr_ChallengeResponse nt;
315 *info3 = NULL;
317 ZERO_STRUCT(zeros);
318 ZERO_STRUCT(ret_creds);
320 ZERO_STRUCT(lm);
321 ZERO_STRUCT(nt);
323 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
324 if (!logon) {
325 return NT_STATUS_NO_MEMORY;
328 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
329 if (!network_info) {
330 return NT_STATUS_NO_MEMORY;
333 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
335 if (server[0] != '\\' && server[1] != '\\') {
336 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
337 } else {
338 server_name_slash = server;
341 if (workstation[0] != '\\' && workstation[1] != '\\') {
342 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
343 } else {
344 workstation_name_slash = workstation;
347 if (!workstation_name_slash || !server_name_slash) {
348 DEBUG(0, ("talloc_asprintf failed!\n"));
349 return NT_STATUS_NO_MEMORY;
352 /* Initialise input parameters */
354 lm.data = lm_response.data;
355 lm.length = lm_response.length;
356 nt.data = nt_response.data;
357 nt.length = nt_response.length;
359 network_info->identity_info.domain_name.string = domain;
360 network_info->identity_info.parameter_control = logon_parameters;
361 network_info->identity_info.logon_id_low = 0xdead;
362 network_info->identity_info.logon_id_high = 0xbeef;
363 network_info->identity_info.account_name.string = username;
364 network_info->identity_info.workstation.string = workstation_name_slash;
366 memcpy(network_info->challenge, chal, 8);
367 network_info->nt = nt;
368 network_info->lm = lm;
370 logon->network = network_info;
372 /* Marshall data and send request */
374 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
375 server_name_slash,
376 global_myname(),
377 &clnt_creds,
378 &ret_creds,
379 NetlogonNetworkInformation,
380 logon,
381 validation_level,
382 &validation,
383 &authoritative);
384 if (!NT_STATUS_IS_OK(result)) {
385 return result;
388 /* Always check returned credentials. */
389 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
390 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
391 return NT_STATUS_ACCESS_DENIED;
394 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
396 *info3 = validation.sam3;
398 return result;
401 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
402 TALLOC_CTX *mem_ctx,
403 uint32 logon_parameters,
404 const char *server,
405 const char *username,
406 const char *domain,
407 const char *workstation,
408 const uint8 chal[8],
409 DATA_BLOB lm_response,
410 DATA_BLOB nt_response,
411 struct netr_SamInfo3 **info3)
413 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
414 int validation_level = 3;
415 const char *workstation_name_slash;
416 const char *server_name_slash;
417 uint8 zeros[16];
418 union netr_LogonLevel *logon = NULL;
419 struct netr_NetworkInfo *network_info;
420 uint8_t authoritative;
421 union netr_Validation validation;
422 struct netr_ChallengeResponse lm;
423 struct netr_ChallengeResponse nt;
424 uint32_t flags = 0;
426 *info3 = NULL;
428 ZERO_STRUCT(zeros);
430 ZERO_STRUCT(lm);
431 ZERO_STRUCT(nt);
433 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
434 if (!logon) {
435 return NT_STATUS_NO_MEMORY;
438 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
439 if (!network_info) {
440 return NT_STATUS_NO_MEMORY;
443 if (server[0] != '\\' && server[1] != '\\') {
444 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
445 } else {
446 server_name_slash = server;
449 if (workstation[0] != '\\' && workstation[1] != '\\') {
450 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
451 } else {
452 workstation_name_slash = workstation;
455 if (!workstation_name_slash || !server_name_slash) {
456 DEBUG(0, ("talloc_asprintf failed!\n"));
457 return NT_STATUS_NO_MEMORY;
460 /* Initialise input parameters */
462 lm.data = lm_response.data;
463 lm.length = lm_response.length;
464 nt.data = nt_response.data;
465 nt.length = nt_response.length;
467 network_info->identity_info.domain_name.string = domain;
468 network_info->identity_info.parameter_control = logon_parameters;
469 network_info->identity_info.logon_id_low = 0xdead;
470 network_info->identity_info.logon_id_high = 0xbeef;
471 network_info->identity_info.account_name.string = username;
472 network_info->identity_info.workstation.string = workstation_name_slash;
474 memcpy(network_info->challenge, chal, 8);
475 network_info->nt = nt;
476 network_info->lm = lm;
478 logon->network = network_info;
480 /* Marshall data and send request */
482 result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
483 server_name_slash,
484 global_myname(),
485 NetlogonNetworkInformation,
486 logon,
487 validation_level,
488 &validation,
489 &authoritative,
490 &flags);
491 if (!NT_STATUS_IS_OK(result)) {
492 return result;
495 netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
497 *info3 = validation.sam3;
499 return result;
502 /*********************************************************
503 Change the domain password on the PDC.
505 Just changes the password betwen the two values specified.
507 Caller must have the cli connected to the netlogon pipe
508 already.
509 **********************************************************/
511 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
512 TALLOC_CTX *mem_ctx,
513 const char *account_name,
514 const unsigned char orig_trust_passwd_hash[16],
515 const char *new_trust_pwd_cleartext,
516 const unsigned char new_trust_passwd_hash[16],
517 enum netr_SchannelType sec_channel_type)
519 NTSTATUS result;
520 struct netr_Authenticator clnt_creds, srv_cred;
522 if (!cli->dc) {
523 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
524 result = rpccli_netlogon_setup_creds(cli,
525 cli->desthost, /* server name */
526 lp_workgroup(), /* domain */
527 global_myname(), /* client name */
528 account_name, /* machine account name */
529 orig_trust_passwd_hash,
530 sec_channel_type,
531 &neg_flags);
532 if (!NT_STATUS_IS_OK(result)) {
533 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
534 nt_errstr(result)));
535 return result;
539 netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
541 if (cli->dc->negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
543 struct netr_CryptPassword new_password;
545 init_netr_CryptPassword(new_trust_pwd_cleartext,
546 cli->dc->session_key,
547 &new_password);
549 result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx,
550 cli->srv_name_slash,
551 cli->dc->account_name,
552 sec_channel_type,
553 cli->dc->computer_name,
554 &clnt_creds,
555 &srv_cred,
556 &new_password);
557 if (!NT_STATUS_IS_OK(result)) {
558 DEBUG(0,("rpccli_netr_ServerPasswordSet2 failed: %s\n",
559 nt_errstr(result)));
560 return result;
562 } else {
564 struct samr_Password new_password;
565 memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash));
566 netlogon_creds_des_encrypt(cli->dc, &new_password);
568 result = rpccli_netr_ServerPasswordSet(cli, mem_ctx,
569 cli->srv_name_slash,
570 cli->dc->account_name,
571 sec_channel_type,
572 cli->dc->computer_name,
573 &clnt_creds,
574 &srv_cred,
575 &new_password);
576 if (!NT_STATUS_IS_OK(result)) {
577 DEBUG(0,("rpccli_netr_ServerPasswordSet failed: %s\n",
578 nt_errstr(result)));
579 return result;
583 /* Always check returned credentials. */
584 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
585 DEBUG(0,("credentials chain check failed\n"));
586 return NT_STATUS_ACCESS_DENIED;
589 return result;