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