s3: Remove some unused variables
[ira/wip.git] / source3 / rpc_client / cli_netlogon.c
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.
8
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.
13
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.
18
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/>.
21 */
22
23 #include "includes.h"
24 #include "../libcli/auth/libcli_auth.h"
25 #include "../librpc/gen_ndr/cli_netlogon.h"
26
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 ****************************************************************************/
32
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)
41 {
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;
48
49         if (!ndr_syntax_id_equal(&cli->abstract_syntax,
50                                  &ndr_table_netlogon.syntax_id)) {
51                 return NT_STATUS_INVALID_PARAMETER;
52         }
53
54         TALLOC_FREE(cli->dc);
55
56         /* Store the machine account password we're going to use. */
57         memcpy(password.hash, machine_pwd, 16);
58
59         fstr_sprintf( mach_acct, "%s$", machine_account);
60
61  again:
62         /* Create the client challenge. */
63         generate_random_buffer(clnt_chal_send.data, 8);
64
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;
73         }
74
75         /* Calculate the session key and client credentials */
76         
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);
85
86         if (!cli->dc) {
87                 return NT_STATUS_NO_MEMORY;
88         }
89
90         /*
91          * Send client auth-2 challenge and receive server repy.
92          */
93
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);
102
103         /* we might be talking to NT4, so let's downgrade in that case and retry
104          * with the returned neg_flags - gd */
105
106         if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
107                 retried = true;
108                 TALLOC_FREE(cli->dc);
109                 goto again;
110         }
111
112         if (!NT_STATUS_IS_OK(result)) {
113                 return result;
114         }
115
116         /*
117          * Check the returned value using the initial
118          * server received challenge.
119          */
120
121         if (!netlogon_creds_client_check(cli->dc, &srv_chal_recv)) {
122                 /*
123                  * Server replied with bad credential. Fail.
124                  */
125                 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
126                         "replied with bad credential\n",
127                         cli->desthost ));
128                 return NT_STATUS_ACCESS_DENIED;
129         }
130
131         DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
132                 "chain established.\n",
133                 cli->desthost ));
134
135         return NT_STATUS_OK;
136 }
137
138 /* Logon domain user */
139
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)
148 {
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
158         ZERO_STRUCT(ret_creds);
159
160         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
161         if (!logon) {
162                 return NT_STATUS_NO_MEMORY;
163         }
164
165         if (workstation) {
166                 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
167         } else {
168                 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
169         }
170
171         /* Initialise input parameters */
172
173         netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
174
175         switch (logon_type) {
176         case NetlogonInteractiveInformation: {
177
178                 struct netr_PasswordInfo *password_info;
179
180                 struct samr_Password lmpassword;
181                 struct samr_Password ntpassword;
182
183                 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
184                 if (!password_info) {
185                         return NT_STATUS_NO_MEMORY;
186                 }
187
188                 nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash);
189
190                 if (cli->dc->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
191                         netlogon_creds_arcfour_crypt(cli->dc, lmpassword.hash, 16);
192                         netlogon_creds_arcfour_crypt(cli->dc, ntpassword.hash, 16);
193                 } else {
194                         netlogon_creds_des_encrypt(cli->dc, &lmpassword);
195                         netlogon_creds_des_encrypt(cli->dc, &ntpassword);
196                 }
197
198                 password_info->identity_info.domain_name.string         = domain;
199                 password_info->identity_info.parameter_control          = logon_parameters;
200                 password_info->identity_info.logon_id_low               = 0xdead;
201                 password_info->identity_info.logon_id_high              = 0xbeef;
202                 password_info->identity_info.account_name.string        = username;
203                 password_info->identity_info.workstation.string         = clnt_name_slash;
204
205                 password_info->lmpassword = lmpassword;
206                 password_info->ntpassword = ntpassword;
207
208                 logon->password = password_info;
209
210                 break;
211         }
212         case NetlogonNetworkInformation: {
213                 struct netr_NetworkInfo *network_info;
214                 uint8 chal[8];
215                 unsigned char local_lm_response[24];
216                 unsigned char local_nt_response[24];
217                 struct netr_ChallengeResponse lm;
218                 struct netr_ChallengeResponse nt;
219
220                 ZERO_STRUCT(lm);
221                 ZERO_STRUCT(nt);
222
223                 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
224                 if (!network_info) {
225                         return NT_STATUS_NO_MEMORY;
226                 }
227
228                 generate_random_buffer(chal, 8);
229
230                 SMBencrypt(password, chal, local_lm_response);
231                 SMBNTencrypt(password, chal, local_nt_response);
232
233                 lm.length = 24;
234                 lm.data = local_lm_response;
235
236                 nt.length = 24;
237                 nt.data = local_nt_response;
238
239                 network_info->identity_info.domain_name.string          = domain;
240                 network_info->identity_info.parameter_control           = logon_parameters;
241                 network_info->identity_info.logon_id_low                = 0xdead;
242                 network_info->identity_info.logon_id_high               = 0xbeef;
243                 network_info->identity_info.account_name.string         = username;
244                 network_info->identity_info.workstation.string          = clnt_name_slash;
245
246                 memcpy(network_info->challenge, chal, 8);
247                 network_info->nt = nt;
248                 network_info->lm = lm;
249
250                 logon->network = network_info;
251
252                 break;
253         }
254         default:
255                 DEBUG(0, ("switch value %d not supported\n",
256                         logon_type));
257                 return NT_STATUS_INVALID_INFO_CLASS;
258         }
259
260         result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
261                                            cli->srv_name_slash,
262                                            global_myname(),
263                                            &clnt_creds,
264                                            &ret_creds,
265                                            logon_type,
266                                            logon,
267                                            validation_level,
268                                            &validation,
269                                            &authoritative);
270
271         /* Always check returned credentials */
272         if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
273                 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
274                 return NT_STATUS_ACCESS_DENIED;
275         }
276
277         return result;
278 }
279
280
281 /**
282  * Logon domain user with an 'network' SAM logon
283  *
284  * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
285  **/
286
287 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
288                                            TALLOC_CTX *mem_ctx,
289                                            uint32 logon_parameters,
290                                            const char *server,
291                                            const char *username,
292                                            const char *domain,
293                                            const char *workstation,
294                                            const uint8 chal[8],
295                                            DATA_BLOB lm_response,
296                                            DATA_BLOB nt_response,
297                                            struct netr_SamInfo3 **info3)
298 {
299         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
300         int validation_level = 3;
301         const char *workstation_name_slash;
302         const char *server_name_slash;
303         struct netr_Authenticator clnt_creds;
304         struct netr_Authenticator ret_creds;
305         union netr_LogonLevel *logon = NULL;
306         struct netr_NetworkInfo *network_info;
307         uint8_t authoritative;
308         union netr_Validation validation;
309         struct netr_ChallengeResponse lm;
310         struct netr_ChallengeResponse nt;
311
312         *info3 = NULL;
313
314         ZERO_STRUCT(ret_creds);
315
316         ZERO_STRUCT(lm);
317         ZERO_STRUCT(nt);
318
319         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
320         if (!logon) {
321                 return NT_STATUS_NO_MEMORY;
322         }
323
324         network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
325         if (!network_info) {
326                 return NT_STATUS_NO_MEMORY;
327         }
328
329         netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
330
331         if (server[0] != '\\' && server[1] != '\\') {
332                 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
333         } else {
334                 server_name_slash = server;
335         }
336
337         if (workstation[0] != '\\' && workstation[1] != '\\') {
338                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
339         } else {
340                 workstation_name_slash = workstation;
341         }
342
343         if (!workstation_name_slash || !server_name_slash) {
344                 DEBUG(0, ("talloc_asprintf failed!\n"));
345                 return NT_STATUS_NO_MEMORY;
346         }
347
348         /* Initialise input parameters */
349
350         lm.data = lm_response.data;
351         lm.length = lm_response.length;
352         nt.data = nt_response.data;
353         nt.length = nt_response.length;
354
355         network_info->identity_info.domain_name.string          = domain;
356         network_info->identity_info.parameter_control           = logon_parameters;
357         network_info->identity_info.logon_id_low                = 0xdead;
358         network_info->identity_info.logon_id_high               = 0xbeef;
359         network_info->identity_info.account_name.string         = username;
360         network_info->identity_info.workstation.string          = workstation_name_slash;
361
362         memcpy(network_info->challenge, chal, 8);
363         network_info->nt = nt;
364         network_info->lm = lm;
365
366         logon->network = network_info;
367
368         /* Marshall data and send request */
369
370         result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
371                                            server_name_slash,
372                                            global_myname(),
373                                            &clnt_creds,
374                                            &ret_creds,
375                                            NetlogonNetworkInformation,
376                                            logon,
377                                            validation_level,
378                                            &validation,
379                                            &authoritative);
380         if (!NT_STATUS_IS_OK(result)) {
381                 return result;
382         }
383
384         /* Always check returned credentials. */
385         if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
386                 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
387                 return NT_STATUS_ACCESS_DENIED;
388         }
389
390         netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
391
392         *info3 = validation.sam3;
393
394         return result;
395 }
396
397 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
398                                               TALLOC_CTX *mem_ctx,
399                                               uint32 logon_parameters,
400                                               const char *server,
401                                               const char *username,
402                                               const char *domain,
403                                               const char *workstation,
404                                               const uint8 chal[8],
405                                               DATA_BLOB lm_response,
406                                               DATA_BLOB nt_response,
407                                               struct netr_SamInfo3 **info3)
408 {
409         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
410         int validation_level = 3;
411         const char *workstation_name_slash;
412         const char *server_name_slash;
413         union netr_LogonLevel *logon = NULL;
414         struct netr_NetworkInfo *network_info;
415         uint8_t authoritative;
416         union netr_Validation validation;
417         struct netr_ChallengeResponse lm;
418         struct netr_ChallengeResponse nt;
419         uint32_t flags = 0;
420
421         *info3 = NULL;
422
423         ZERO_STRUCT(lm);
424         ZERO_STRUCT(nt);
425
426         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
427         if (!logon) {
428                 return NT_STATUS_NO_MEMORY;
429         }
430
431         network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
432         if (!network_info) {
433                 return NT_STATUS_NO_MEMORY;
434         }
435
436         if (server[0] != '\\' && server[1] != '\\') {
437                 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
438         } else {
439                 server_name_slash = server;
440         }
441
442         if (workstation[0] != '\\' && workstation[1] != '\\') {
443                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
444         } else {
445                 workstation_name_slash = workstation;
446         }
447
448         if (!workstation_name_slash || !server_name_slash) {
449                 DEBUG(0, ("talloc_asprintf failed!\n"));
450                 return NT_STATUS_NO_MEMORY;
451         }
452
453         /* Initialise input parameters */
454
455         lm.data = lm_response.data;
456         lm.length = lm_response.length;
457         nt.data = nt_response.data;
458         nt.length = nt_response.length;
459
460         network_info->identity_info.domain_name.string          = domain;
461         network_info->identity_info.parameter_control           = logon_parameters;
462         network_info->identity_info.logon_id_low                = 0xdead;
463         network_info->identity_info.logon_id_high               = 0xbeef;
464         network_info->identity_info.account_name.string         = username;
465         network_info->identity_info.workstation.string          = workstation_name_slash;
466
467         memcpy(network_info->challenge, chal, 8);
468         network_info->nt = nt;
469         network_info->lm = lm;
470
471         logon->network = network_info;
472
473         /* Marshall data and send request */
474
475         result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
476                                              server_name_slash,
477                                              global_myname(),
478                                              NetlogonNetworkInformation,
479                                              logon,
480                                              validation_level,
481                                              &validation,
482                                              &authoritative,
483                                              &flags);
484         if (!NT_STATUS_IS_OK(result)) {
485                 return result;
486         }
487
488         netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
489
490         *info3 = validation.sam3;
491
492         return result;
493 }
494
495 /*********************************************************
496  Change the domain password on the PDC.
497
498  Just changes the password betwen the two values specified.
499
500  Caller must have the cli connected to the netlogon pipe
501  already.
502 **********************************************************/
503
504 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
505                                             TALLOC_CTX *mem_ctx,
506                                             const char *account_name,
507                                             const unsigned char orig_trust_passwd_hash[16],
508                                             const char *new_trust_pwd_cleartext,
509                                             const unsigned char new_trust_passwd_hash[16],
510                                             enum netr_SchannelType sec_channel_type)
511 {
512         NTSTATUS result;
513         struct netr_Authenticator clnt_creds, srv_cred;
514
515         if (!cli->dc) {
516                 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
517                 result = rpccli_netlogon_setup_creds(cli,
518                                                      cli->desthost, /* server name */
519                                                      lp_workgroup(), /* domain */
520                                                      global_myname(), /* client name */
521                                                      account_name, /* machine account name */
522                                                      orig_trust_passwd_hash,
523                                                      sec_channel_type,
524                                                      &neg_flags);
525                 if (!NT_STATUS_IS_OK(result)) {
526                         DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
527                                  nt_errstr(result)));
528                         return result;
529                 }
530         }
531
532         netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
533
534         if (cli->dc->negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
535
536                 struct netr_CryptPassword new_password;
537
538                 init_netr_CryptPassword(new_trust_pwd_cleartext,
539                                         cli->dc->session_key,
540                                         &new_password);
541
542                 result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx,
543                                                         cli->srv_name_slash,
544                                                         cli->dc->account_name,
545                                                         sec_channel_type,
546                                                         cli->dc->computer_name,
547                                                         &clnt_creds,
548                                                         &srv_cred,
549                                                         &new_password);
550                 if (!NT_STATUS_IS_OK(result)) {
551                         DEBUG(0,("rpccli_netr_ServerPasswordSet2 failed: %s\n",
552                                 nt_errstr(result)));
553                         return result;
554                 }
555         } else {
556
557                 struct samr_Password new_password;
558                 memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash));
559                 netlogon_creds_des_encrypt(cli->dc, &new_password);
560
561                 result = rpccli_netr_ServerPasswordSet(cli, mem_ctx,
562                                                        cli->srv_name_slash,
563                                                        cli->dc->account_name,
564                                                        sec_channel_type,
565                                                        cli->dc->computer_name,
566                                                        &clnt_creds,
567                                                        &srv_cred,
568                                                        &new_password);
569                 if (!NT_STATUS_IS_OK(result)) {
570                         DEBUG(0,("rpccli_netr_ServerPasswordSet failed: %s\n",
571                                 nt_errstr(result)));
572                         return result;
573                 }
574         }
575
576         /* Always check returned credentials. */
577         if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
578                 DEBUG(0,("credentials chain check failed\n"));
579                 return NT_STATUS_ACCESS_DENIED;
580         }
581
582         return result;
583 }
584