error-codes: add some service related error codes.
[Samba/bb.git] / source / rpc_client / cli_netlogon.c
blob23618efd9fc9482a4a5037ed23176976e5fcc461
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;
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
548 already.
549 **********************************************************/
551 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
552 TALLOC_CTX *mem_ctx,
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)
558 NTSTATUS result;
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,
568 sec_channel_type,
569 &neg_flags);
571 if (!NT_STATUS_IS_OK(result)) {
572 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
573 nt_errstr(result)));
574 return result;
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,
584 cli->dc->sess_key,
585 &new_password);
587 result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx,
588 cli->dc->remote_machine,
589 cli->dc->mach_acct,
590 sec_channel_type,
591 global_myname(),
592 &clnt_creds,
593 &srv_cred,
594 &new_password);
595 if (!NT_STATUS_IS_OK(result)) {
596 DEBUG(0,("rpccli_netr_ServerPasswordSet2 failed: %s\n",
597 nt_errstr(result)));
598 return result;
600 } else {
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,
610 cli->dc->mach_acct,
611 sec_channel_type,
612 global_myname(),
613 &clnt_creds,
614 &srv_cred,
615 &new_password);
616 if (!NT_STATUS_IS_OK(result)) {
617 DEBUG(0,("rpccli_netr_ServerPasswordSet failed: %s\n",
618 nt_errstr(result)));
619 return result;
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;
629 return result;