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