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/>.
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
30 ****************************************************************************/
32 NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
33 const char *server_name,
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;
47 SMB_ASSERT(ndr_syntax_id_equal(&cli->abstract_syntax,
48 &ndr_table_netlogon.syntax_id));
51 cli->dc = talloc_zero(cli, struct dcinfo);
52 if (cli->dc == NULL) {
53 return NT_STATUS_NO_MEMORY;
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);
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(),
77 if (!NT_STATUS_IS_OK(result)) {
81 /* Calculate the session key and client credentials */
82 creds_client_init(*neg_flags_inout,
90 * Send client auth-2 challenge and receive server repy.
93 result = rpccli_netr_ServerAuthenticate2(cli, talloc_tos(),
98 &clnt_chal_send, /* input. */
99 &srv_chal_recv, /* output. */
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) {
110 if (!NT_STATUS_IS_OK(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",
126 return NT_STATUS_ACCESS_DENIED;
129 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
130 "chain established.\n",
136 /* Logon domain user */
138 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
140 uint32 logon_parameters,
142 const char *username,
143 const char *password,
144 const char *workstation,
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;
157 ZERO_STRUCT(ret_creds);
160 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
162 return NT_STATUS_NO_MEMORY;
166 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
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);
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);
218 memcpy(lmpassword.hash, lm_owf, 16);
219 memcpy(ntpassword.hash, nt_owf, 16);
221 init_netr_PasswordInfo(password_info,
231 logon->password = password_info;
235 case NetlogonNetworkInformation: {
236 struct netr_NetworkInfo *network_info;
238 unsigned char local_lm_response[24];
239 unsigned char local_nt_response[24];
240 struct netr_ChallengeResponse lm;
241 struct netr_ChallengeResponse nt;
246 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
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);
257 lm.data = local_lm_response;
260 nt.data = local_nt_response;
262 init_netr_NetworkInfo(network_info,
273 logon->network = network_info;
278 DEBUG(0, ("switch value %d not supported\n",
280 return NT_STATUS_INVALID_INFO_CLASS;
283 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
284 cli->dc->remote_machine,
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;
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,
314 uint32 logon_parameters,
316 const char *username,
318 const char *workstation,
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;
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;
341 ZERO_STRUCT(ret_creds);
346 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
348 return NT_STATUS_NO_MEMORY;
351 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
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);
361 server_name_slash = server;
364 if (workstation[0] != '\\' && workstation[1] != '\\') {
365 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
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,
388 workstation_name_slash,
393 logon->network = network_info;
395 /* Marshall data and send request */
397 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
402 NetlogonNetworkInformation,
407 if (!NT_STATUS_IS_OK(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;
434 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
436 uint32 logon_parameters,
438 const char *username,
440 const char *workstation,
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;
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;
466 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
468 return NT_STATUS_NO_MEMORY;
471 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
473 return NT_STATUS_NO_MEMORY;
476 if (server[0] != '\\' && server[1] != '\\') {
477 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
479 server_name_slash = server;
482 if (workstation[0] != '\\' && workstation[1] != '\\') {
483 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
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,
506 workstation_name_slash,
511 logon->network = network_info;
513 /* Marshall data and send request */
515 result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
518 NetlogonNetworkInformation,
524 if (!NT_STATUS_IS_OK(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;
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
550 **********************************************************/
552 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
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)
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,
572 if (!NT_STATUS_IS_OK(result)) {
573 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
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,
588 result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx,
589 cli->dc->remote_machine,
596 if (!NT_STATUS_IS_OK(result)) {
597 DEBUG(0,("rpccli_netr_ServerPasswordSet2 failed: %s\n",
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,
617 if (!NT_STATUS_IS_OK(result)) {
618 DEBUG(0,("rpccli_netr_ServerPasswordSet failed: %s\n",
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;