OS/X does not have rl_done in readline.h
[Samba.git] / source / rpc_client / cli_netlogon.c
blobdf87ed13d132ddd97bbd3f2da255e5516d3cdc06
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"
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
28 netlogon pipe struct.
29 ****************************************************************************/
31 NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
32 const char *server_name,
33 const char *domain,
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;
43 struct dcinfo *dc;
44 bool retried = false;
46 SMB_ASSERT(ndr_syntax_id_equal(&cli->abstract_syntax,
47 &ndr_table_netlogon.syntax_id));
49 TALLOC_FREE(cli->dc);
50 cli->dc = talloc_zero(cli, struct dcinfo);
51 if (cli->dc == NULL) {
52 return NT_STATUS_NO_MEMORY;
54 dc = cli->dc;
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);
66 again:
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(),
72 dc->remote_machine,
73 clnt_name,
74 &clnt_chal_send,
75 &srv_chal_recv);
76 if (!NT_STATUS_IS_OK(result)) {
77 return result;
80 /* Calculate the session key and client credentials */
81 creds_client_init(*neg_flags_inout,
82 dc,
83 &clnt_chal_send,
84 &srv_chal_recv,
85 machine_pwd,
86 &clnt_chal_send);
89 * Send client auth-2 challenge and receive server repy.
92 result = rpccli_netr_ServerAuthenticate2(cli, talloc_tos(),
93 dc->remote_machine,
94 dc->mach_acct,
95 sec_chan_type,
96 clnt_name,
97 &clnt_chal_send, /* input. */
98 &srv_chal_recv, /* output. */
99 neg_flags_inout);
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) {
105 retried = true;
106 goto again;
109 if (!NT_STATUS_IS_OK(result)) {
110 return 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",
124 cli->desthost ));
125 return NT_STATUS_ACCESS_DENIED;
128 DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
129 "chain established.\n",
130 cli->desthost ));
132 return NT_STATUS_OK;
135 /* Logon domain user */
137 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
138 TALLOC_CTX *mem_ctx,
139 uint32 logon_parameters,
140 const char *domain,
141 const char *username,
142 const char *password,
143 const char *workstation,
144 int logon_type)
146 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
147 struct netr_Authenticator clnt_creds;
148 struct netr_Authenticator ret_creds;
149 union netr_LogonInfo *logon;
150 union netr_Validation validation;
151 uint8_t authoritative;
152 int validation_level = 3;
153 fstring clnt_name_slash;
154 uint8 zeros[16];
156 ZERO_STRUCT(ret_creds);
157 ZERO_STRUCT(zeros);
159 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
160 if (!logon) {
161 return NT_STATUS_NO_MEMORY;
164 if (workstation) {
165 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
166 } else {
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 INTERACTIVE_LOGON_TYPE: {
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);
201 #endif
202 memset(key, 0, 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);
216 #endif
217 memcpy(lmpassword.hash, lm_owf, 16);
218 memcpy(ntpassword.hash, nt_owf, 16);
220 init_netr_PasswordInfo(password_info,
221 domain,
222 logon_parameters,
223 0xdead,
224 0xbeef,
225 username,
226 clnt_name_slash,
227 lmpassword,
228 ntpassword);
230 logon->password = password_info;
232 break;
234 case NET_LOGON_TYPE: {
235 struct netr_NetworkInfo *network_info;
236 uint8 chal[8];
237 unsigned char local_lm_response[24];
238 unsigned char local_nt_response[24];
239 struct netr_ChallengeResponse lm;
240 struct netr_ChallengeResponse nt;
242 ZERO_STRUCT(lm);
243 ZERO_STRUCT(nt);
245 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
246 if (!network_info) {
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);
255 lm.length = 24;
256 lm.data = local_lm_response;
258 nt.length = 24;
259 nt.data = local_nt_response;
261 init_netr_NetworkInfo(network_info,
262 domain,
263 logon_parameters,
264 0xdead,
265 0xbeef,
266 username,
267 clnt_name_slash,
268 chal,
270 lm);
272 logon->network = network_info;
274 break;
276 default:
277 DEBUG(0, ("switch value %d not supported\n",
278 logon_type));
279 return NT_STATUS_INVALID_INFO_CLASS;
282 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
283 cli->dc->remote_machine,
284 global_myname(),
285 &clnt_creds,
286 &ret_creds,
287 logon_type,
288 logon,
289 validation_level,
290 &validation,
291 &authoritative);
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;
301 return result;
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,
312 TALLOC_CTX *mem_ctx,
313 uint32 logon_parameters,
314 const char *server,
315 const char *username,
316 const char *domain,
317 const char *workstation,
318 const uint8 chal[8],
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;
327 uint8 zeros[16];
328 struct netr_Authenticator clnt_creds;
329 struct netr_Authenticator ret_creds;
330 union netr_LogonInfo *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;
337 *info3 = NULL;
339 ZERO_STRUCT(zeros);
340 ZERO_STRUCT(ret_creds);
342 ZERO_STRUCT(lm);
343 ZERO_STRUCT(nt);
345 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
346 if (!logon) {
347 return NT_STATUS_NO_MEMORY;
350 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
351 if (!network_info) {
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);
359 } else {
360 server_name_slash = server;
363 if (workstation[0] != '\\' && workstation[1] != '\\') {
364 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
365 } else {
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,
382 domain,
383 logon_parameters,
384 0xdead,
385 0xbeef,
386 username,
387 workstation_name_slash,
388 (uint8_t *) chal,
390 lm);
392 logon->network = network_info;
394 /* Marshall data and send request */
396 result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
397 server_name_slash,
398 global_myname(),
399 &clnt_creds,
400 &ret_creds,
401 NET_LOGON_TYPE,
402 logon,
403 validation_level,
404 &validation,
405 &authoritative);
406 if (!NT_STATUS_IS_OK(result)) {
407 return 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;
430 return result;
433 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
434 TALLOC_CTX *mem_ctx,
435 uint32 logon_parameters,
436 const char *server,
437 const char *username,
438 const char *domain,
439 const char *workstation,
440 const uint8 chal[8],
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;
449 uint8 zeros[16];
450 union netr_LogonInfo *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;
456 uint32_t flags = 0;
458 *info3 = NULL;
460 ZERO_STRUCT(zeros);
462 ZERO_STRUCT(lm);
463 ZERO_STRUCT(nt);
465 logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
466 if (!logon) {
467 return NT_STATUS_NO_MEMORY;
470 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
471 if (!network_info) {
472 return NT_STATUS_NO_MEMORY;
475 if (server[0] != '\\' && server[1] != '\\') {
476 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
477 } else {
478 server_name_slash = server;
481 if (workstation[0] != '\\' && workstation[1] != '\\') {
482 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
483 } else {
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,
500 domain,
501 logon_parameters,
502 0xdead,
503 0xbeef,
504 username,
505 workstation_name_slash,
506 (uint8_t *) chal,
508 lm);
510 logon->network = network_info;
512 /* Marshall data and send request */
514 result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
515 server_name_slash,
516 global_myname(),
517 NET_LOGON_TYPE,
518 logon,
519 validation_level,
520 &validation,
521 &authoritative,
522 &flags);
523 if (!NT_STATUS_IS_OK(result)) {
524 return 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;
539 return result;