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