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/>.
25 /****************************************************************************
26 Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
27 credentials chain. Stores the credentials in the struct dcinfo in the
29 ****************************************************************************/
31 NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
32 const char *server_name,
34 const char *clnt_name,
35 const char *machine_account,
36 const unsigned char machine_pwd[16],
37 enum netr_SchannelType sec_chan_type,
38 uint32_t *neg_flags_inout)
40 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
41 struct netr_Credential clnt_chal_send;
42 struct netr_Credential srv_chal_recv;
46 SMB_ASSERT(ndr_syntax_id_equal(&cli->abstract_syntax,
47 &ndr_table_netlogon.syntax_id));
50 cli->dc = talloc_zero(cli, struct dcinfo);
51 if (cli->dc == NULL) {
52 return NT_STATUS_NO_MEMORY;
56 /* Store the machine account password we're going to use. */
57 memcpy(dc->mach_pw, machine_pwd, 16);
59 fstrcpy(dc->remote_machine, "\\\\");
60 fstrcat(dc->remote_machine, server_name);
62 fstrcpy(dc->domain, domain);
64 fstr_sprintf( dc->mach_acct, "%s$", machine_account);
67 /* Create the client challenge. */
68 generate_random_buffer(clnt_chal_send.data, 8);
70 /* Get the server challenge. */
71 result = rpccli_netr_ServerReqChallenge(cli, talloc_tos(),
76 if (!NT_STATUS_IS_OK(result)) {
80 /* Calculate the session key and client credentials */
81 creds_client_init(*neg_flags_inout,
89 * Send client auth-2 challenge and receive server repy.
92 result = rpccli_netr_ServerAuthenticate2(cli, talloc_tos(),
97 &clnt_chal_send, /* input. */
98 &srv_chal_recv, /* output. */
101 /* we might be talking to NT4, so let's downgrade in that case and retry
102 * with the returned neg_flags - gd */
104 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
109 if (!NT_STATUS_IS_OK(result)) {
114 * Check the returned value using the initial
115 * server received challenge.
118 if (!netlogon_creds_client_check(dc, &srv_chal_recv)) {
120 * Server replied with bad credential. Fail.
122 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
123 "replied with bad credential\n",
125 return NT_STATUS_ACCESS_DENIED;
128 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
129 "chain established.\n",
135 /* Logon domain user */
137 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
139 uint32 logon_parameters,
141 const char *username,
142 const char *password,
143 const char *workstation,
146 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
147 struct netr_Authenticator clnt_creds;
148 struct netr_Authenticator ret_creds;
149 union netr_LogonLevel *logon;
150 union netr_Validation validation;
151 uint8_t authoritative;
152 int validation_level = 3;
153 fstring clnt_name_slash;
156 ZERO_STRUCT(ret_creds);
159 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
161 return NT_STATUS_NO_MEMORY;
165 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
167 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
170 /* Initialise input parameters */
172 netlogon_creds_client_step(cli->dc, &clnt_creds);
174 switch (logon_type) {
175 case NetlogonInteractiveInformation: {
177 struct netr_PasswordInfo *password_info;
179 struct samr_Password lmpassword;
180 struct samr_Password ntpassword;
182 unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16];
184 unsigned char lm_owf[16];
185 unsigned char nt_owf[16];
186 unsigned char key[16];
188 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
189 if (!password_info) {
190 return NT_STATUS_NO_MEMORY;
193 nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd);
195 #ifdef DEBUG_PASSWORD
196 DEBUG(100,("lm cypher:"));
197 dump_data(100, lm_owf_user_pwd, 16);
199 DEBUG(100,("nt cypher:"));
200 dump_data(100, nt_owf_user_pwd, 16);
203 memcpy(key, cli->dc->sess_key, 8);
205 memcpy(lm_owf, lm_owf_user_pwd, 16);
206 SamOEMhash(lm_owf, key, 16);
207 memcpy(nt_owf, nt_owf_user_pwd, 16);
208 SamOEMhash(nt_owf, key, 16);
210 #ifdef DEBUG_PASSWORD
211 DEBUG(100,("encrypt of lm owf password:"));
212 dump_data(100, lm_owf, 16);
214 DEBUG(100,("encrypt of nt owf password:"));
215 dump_data(100, nt_owf, 16);
217 memcpy(lmpassword.hash, lm_owf, 16);
218 memcpy(ntpassword.hash, nt_owf, 16);
220 init_netr_PasswordInfo(password_info,
230 logon->password = password_info;
234 case NetlogonNetworkInformation: {
235 struct netr_NetworkInfo *network_info;
237 unsigned char local_lm_response[24];
238 unsigned char local_nt_response[24];
239 struct netr_ChallengeResponse lm;
240 struct netr_ChallengeResponse nt;
245 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
247 return NT_STATUS_NO_MEMORY;
250 generate_random_buffer(chal, 8);
252 SMBencrypt(password, chal, local_lm_response);
253 SMBNTencrypt(password, chal, local_nt_response);
256 lm.data = local_lm_response;
259 nt.data = local_nt_response;
261 init_netr_NetworkInfo(network_info,
272 logon->network = network_info;
277 DEBUG(0, ("switch value %d not supported\n",
279 return NT_STATUS_INVALID_INFO_CLASS;
282 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
283 cli->dc->remote_machine,
293 if (memcmp(zeros, &ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
294 /* Check returned credentials if present. */
295 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
296 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
297 return NT_STATUS_ACCESS_DENIED;
306 * Logon domain user with an 'network' SAM logon
308 * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
311 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
313 uint32 logon_parameters,
315 const char *username,
317 const char *workstation,
319 DATA_BLOB lm_response,
320 DATA_BLOB nt_response,
321 struct netr_SamInfo3 **info3)
323 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
324 int validation_level = 3;
325 const char *workstation_name_slash;
326 const char *server_name_slash;
328 struct netr_Authenticator clnt_creds;
329 struct netr_Authenticator ret_creds;
330 union netr_LogonLevel *logon = NULL;
331 struct netr_NetworkInfo *network_info;
332 uint8_t authoritative;
333 union netr_Validation validation;
334 struct netr_ChallengeResponse lm;
335 struct netr_ChallengeResponse nt;
340 ZERO_STRUCT(ret_creds);
345 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
347 return NT_STATUS_NO_MEMORY;
350 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
352 return NT_STATUS_NO_MEMORY;
355 netlogon_creds_client_step(cli->dc, &clnt_creds);
357 if (server[0] != '\\' && server[1] != '\\') {
358 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
360 server_name_slash = server;
363 if (workstation[0] != '\\' && workstation[1] != '\\') {
364 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
366 workstation_name_slash = workstation;
369 if (!workstation_name_slash || !server_name_slash) {
370 DEBUG(0, ("talloc_asprintf failed!\n"));
371 return NT_STATUS_NO_MEMORY;
374 /* Initialise input parameters */
376 lm.data = lm_response.data;
377 lm.length = lm_response.length;
378 nt.data = nt_response.data;
379 nt.length = nt_response.length;
381 init_netr_NetworkInfo(network_info,
387 workstation_name_slash,
392 logon->network = network_info;
394 /* Marshall data and send request */
396 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
401 NetlogonNetworkInformation,
406 if (!NT_STATUS_IS_OK(result)) {
410 if (memcmp(zeros, validation.sam3->base.key.key, 16) != 0) {
411 SamOEMhash(validation.sam3->base.key.key,
412 cli->dc->sess_key, 16);
415 if (memcmp(zeros, validation.sam3->base.LMSessKey.key, 8) != 0) {
416 SamOEMhash(validation.sam3->base.LMSessKey.key,
417 cli->dc->sess_key, 8);
420 if (memcmp(zeros, ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
421 /* Check returned credentials if present. */
422 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
423 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
424 return NT_STATUS_ACCESS_DENIED;
428 *info3 = validation.sam3;
433 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
435 uint32 logon_parameters,
437 const char *username,
439 const char *workstation,
441 DATA_BLOB lm_response,
442 DATA_BLOB nt_response,
443 struct netr_SamInfo3 **info3)
445 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
446 int validation_level = 3;
447 const char *workstation_name_slash;
448 const char *server_name_slash;
450 union netr_LogonLevel *logon = NULL;
451 struct netr_NetworkInfo *network_info;
452 uint8_t authoritative;
453 union netr_Validation validation;
454 struct netr_ChallengeResponse lm;
455 struct netr_ChallengeResponse nt;
465 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
467 return NT_STATUS_NO_MEMORY;
470 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
472 return NT_STATUS_NO_MEMORY;
475 if (server[0] != '\\' && server[1] != '\\') {
476 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
478 server_name_slash = server;
481 if (workstation[0] != '\\' && workstation[1] != '\\') {
482 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
484 workstation_name_slash = workstation;
487 if (!workstation_name_slash || !server_name_slash) {
488 DEBUG(0, ("talloc_asprintf failed!\n"));
489 return NT_STATUS_NO_MEMORY;
492 /* Initialise input parameters */
494 lm.data = lm_response.data;
495 lm.length = lm_response.length;
496 nt.data = nt_response.data;
497 nt.length = nt_response.length;
499 init_netr_NetworkInfo(network_info,
505 workstation_name_slash,
510 logon->network = network_info;
512 /* Marshall data and send request */
514 result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
517 NetlogonNetworkInformation,
523 if (!NT_STATUS_IS_OK(result)) {
527 if (memcmp(zeros, validation.sam3->base.key.key, 16) != 0) {
528 SamOEMhash(validation.sam3->base.key.key,
529 cli->dc->sess_key, 16);
532 if (memcmp(zeros, validation.sam3->base.LMSessKey.key, 8) != 0) {
533 SamOEMhash(validation.sam3->base.LMSessKey.key,
534 cli->dc->sess_key, 8);
537 *info3 = validation.sam3;
542 /*********************************************************
543 Change the domain password on the PDC.
545 Just changes the password betwen the two values specified.
547 Caller must have the cli connected to the netlogon pipe
549 **********************************************************/
551 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
553 const unsigned char orig_trust_passwd_hash[16],
554 const char *new_trust_pwd_cleartext,
555 const unsigned char new_trust_passwd_hash[16],
556 uint32_t sec_channel_type)
559 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
560 struct netr_Authenticator clnt_creds, srv_cred;
562 result = rpccli_netlogon_setup_creds(cli,
563 cli->desthost, /* server name */
564 lp_workgroup(), /* domain */
565 global_myname(), /* client name */
566 global_myname(), /* machine account name */
567 orig_trust_passwd_hash,
571 if (!NT_STATUS_IS_OK(result)) {
572 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
577 netlogon_creds_client_step(cli->dc, &clnt_creds);
579 if (neg_flags & NETLOGON_NEG_PASSWORD_SET2) {
581 struct netr_CryptPassword new_password;
583 init_netr_CryptPassword(new_trust_pwd_cleartext,
587 result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx,
588 cli->dc->remote_machine,
595 if (!NT_STATUS_IS_OK(result)) {
596 DEBUG(0,("rpccli_netr_ServerPasswordSet2 failed: %s\n",
602 struct samr_Password new_password;
604 cred_hash3(new_password.hash,
605 new_trust_passwd_hash,
606 cli->dc->sess_key, 1);
608 result = rpccli_netr_ServerPasswordSet(cli, mem_ctx,
609 cli->dc->remote_machine,
616 if (!NT_STATUS_IS_OK(result)) {
617 DEBUG(0,("rpccli_netr_ServerPasswordSet failed: %s\n",
623 /* Always check returned credentials. */
624 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
625 DEBUG(0,("credentials chain check failed\n"));
626 return NT_STATUS_ACCESS_DENIED;