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