762802d327806acade61559c8b4ace4a2cdc88de
[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 "system/filesys.h"
25 #include "libsmb/libsmb.h"
26 #include "rpc_client/rpc_client.h"
27 #include "rpc_client/cli_pipe.h"
28 #include "../libcli/auth/libcli_auth.h"
29 #include "../libcli/auth/netlogon_creds_cli.h"
30 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
31 #include "../librpc/gen_ndr/schannel.h"
32 #include "rpc_client/cli_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 #include "dbwrap/dbwrap.h"
38 #include "dbwrap/dbwrap_open.h"
39 #include "util_tdb.h"
40 #include "lib/crypto/gnutls_helpers.h"
41
42
43 NTSTATUS rpccli_pre_open_netlogon_creds(void)
44 {
45         static bool already_open = false;
46         TALLOC_CTX *frame;
47         struct loadparm_context *lp_ctx;
48         char *fname;
49         struct db_context *global_db;
50         NTSTATUS status;
51
52         if (already_open) {
53                 return NT_STATUS_OK;
54         }
55
56         frame = talloc_stackframe();
57
58         lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
59         if (lp_ctx == NULL) {
60                 TALLOC_FREE(frame);
61                 return NT_STATUS_NO_MEMORY;
62         }
63
64         fname = lpcfg_private_db_path(frame, lp_ctx, "netlogon_creds_cli");
65         if (fname == NULL) {
66                 TALLOC_FREE(frame);
67                 return NT_STATUS_NO_MEMORY;
68         }
69
70         global_db = db_open(frame, fname,
71                             0, TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
72                             O_RDWR|O_CREAT, 0600, DBWRAP_LOCK_ORDER_2,
73                             DBWRAP_FLAG_OPTIMIZE_READONLY_ACCESS);
74         if (global_db == NULL) {
75                 TALLOC_FREE(frame);
76                 return NT_STATUS_NO_MEMORY;
77         }
78
79         status = netlogon_creds_cli_set_global_db(lp_ctx, &global_db);
80         TALLOC_FREE(frame);
81         if (!NT_STATUS_IS_OK(status)) {
82                 return status;
83         }
84
85         already_open = true;
86         return NT_STATUS_OK;
87 }
88
89 static NTSTATUS rpccli_create_netlogon_creds(
90         const char *server_computer,
91         const char *server_netbios_domain,
92         const char *server_dns_domain,
93         const char *client_account,
94         enum netr_SchannelType sec_chan_type,
95         struct messaging_context *msg_ctx,
96         TALLOC_CTX *mem_ctx,
97         struct netlogon_creds_cli_context **netlogon_creds)
98 {
99         TALLOC_CTX *frame = talloc_stackframe();
100         struct loadparm_context *lp_ctx;
101         NTSTATUS status;
102
103         status = rpccli_pre_open_netlogon_creds();
104         if (!NT_STATUS_IS_OK(status)) {
105                 TALLOC_FREE(frame);
106                 return status;
107         }
108
109         lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
110         if (lp_ctx == NULL) {
111                 TALLOC_FREE(frame);
112                 return NT_STATUS_NO_MEMORY;
113         }
114         status = netlogon_creds_cli_context_global(lp_ctx,
115                                                    msg_ctx,
116                                                    client_account,
117                                                    sec_chan_type,
118                                                    server_computer,
119                                                    server_netbios_domain,
120                                                    server_dns_domain,
121                                                    mem_ctx, netlogon_creds);
122         TALLOC_FREE(frame);
123         if (!NT_STATUS_IS_OK(status)) {
124                 return status;
125         }
126
127         return NT_STATUS_OK;
128 }
129
130 NTSTATUS rpccli_create_netlogon_creds_ctx(
131         struct cli_credentials *creds,
132         const char *server_computer,
133         struct messaging_context *msg_ctx,
134         TALLOC_CTX *mem_ctx,
135         struct netlogon_creds_cli_context **creds_ctx)
136 {
137         enum netr_SchannelType sec_chan_type;
138         const char *server_netbios_domain;
139         const char *server_dns_domain;
140         const char *client_account;
141
142         sec_chan_type = cli_credentials_get_secure_channel_type(creds);
143         client_account = cli_credentials_get_username(creds);
144         server_netbios_domain = cli_credentials_get_domain(creds);
145         server_dns_domain = cli_credentials_get_realm(creds);
146
147         return rpccli_create_netlogon_creds(server_computer,
148                                             server_netbios_domain,
149                                             server_dns_domain,
150                                             client_account,
151                                             sec_chan_type,
152                                             msg_ctx, mem_ctx,
153                                             creds_ctx);
154 }
155
156 NTSTATUS rpccli_setup_netlogon_creds_locked(
157         struct cli_state *cli,
158         enum dcerpc_transport_t transport,
159         struct netlogon_creds_cli_context *creds_ctx,
160         bool force_reauth,
161         struct cli_credentials *cli_creds,
162         uint32_t *negotiate_flags)
163 {
164         TALLOC_CTX *frame = talloc_stackframe();
165         struct rpc_pipe_client *netlogon_pipe = NULL;
166         struct netlogon_creds_CredentialState *creds = NULL;
167         uint8_t num_nt_hashes = 0;
168         const struct samr_Password *nt_hashes[2] = { NULL, NULL };
169         uint8_t idx_nt_hashes = 0;
170         NTSTATUS status;
171         const char *remote_name = NULL;
172         const struct sockaddr_storage *remote_sockaddr = NULL;
173
174         status = netlogon_creds_cli_get(creds_ctx, frame, &creds);
175         if (NT_STATUS_IS_OK(status)) {
176                 const char *action = "using";
177
178                 if (force_reauth) {
179                         action = "overwrite";
180                 }
181
182                 if (cli != NULL) {
183                         remote_name = smbXcli_conn_remote_name(cli->conn);
184                 } else {
185                         remote_name = "<UNKNOWN>";
186                 }
187
188                 DEBUG(5,("%s: %s cached netlogon_creds cli[%s/%s] to %s\n",
189                          __FUNCTION__, action,
190                          creds->account_name, creds->computer_name,
191                          remote_name));
192                 if (!force_reauth) {
193                         goto done;
194                 }
195                 TALLOC_FREE(creds);
196         }
197
198         nt_hashes[0] = cli_credentials_get_nt_hash(cli_creds, talloc_tos());
199         if (nt_hashes[0] == NULL) {
200                 TALLOC_FREE(frame);
201                 return NT_STATUS_NO_MEMORY;
202         }
203         num_nt_hashes = 1;
204
205         nt_hashes[1] = cli_credentials_get_old_nt_hash(cli_creds,
206                                                        talloc_tos());
207         if (nt_hashes[1] != NULL) {
208                 num_nt_hashes = 2;
209         }
210
211         remote_name = smbXcli_conn_remote_name(cli->conn);
212         remote_sockaddr = smbXcli_conn_remote_sockaddr(cli->conn);
213
214         status = cli_rpc_pipe_open_noauth_transport(cli,
215                                                     transport,
216                                                     &ndr_table_netlogon,
217                                                     remote_name,
218                                                     remote_sockaddr,
219                                                     &netlogon_pipe);
220         if (!NT_STATUS_IS_OK(status)) {
221                 DEBUG(5,("%s: failed to open noauth netlogon connection to %s - %s\n",
222                          __FUNCTION__,
223                          remote_name,
224                          nt_errstr(status)));
225                 TALLOC_FREE(frame);
226                 return status;
227         }
228         talloc_steal(frame, netlogon_pipe);
229
230         status = netlogon_creds_cli_auth(creds_ctx,
231                                          netlogon_pipe->binding_handle,
232                                          num_nt_hashes,
233                                          nt_hashes,
234                                          &idx_nt_hashes);
235         if (!NT_STATUS_IS_OK(status)) {
236                 TALLOC_FREE(frame);
237                 return status;
238         }
239
240         status = netlogon_creds_cli_get(creds_ctx, frame, &creds);
241         if (!NT_STATUS_IS_OK(status)) {
242                 TALLOC_FREE(frame);
243                 return NT_STATUS_INTERNAL_ERROR;
244         }
245
246         DEBUG(5,("%s: using new netlogon_creds cli[%s/%s] to %s\n",
247                  __FUNCTION__,
248                  creds->account_name, creds->computer_name,
249                  remote_name));
250
251 done:
252         if (negotiate_flags != NULL) {
253                 *negotiate_flags = creds->negotiate_flags;
254         }
255
256         TALLOC_FREE(frame);
257         return NT_STATUS_OK;
258 }
259
260 NTSTATUS rpccli_setup_netlogon_creds(
261         struct cli_state *cli,
262         enum dcerpc_transport_t transport,
263         struct netlogon_creds_cli_context *creds_ctx,
264         bool force_reauth,
265         struct cli_credentials *cli_creds)
266 {
267         TALLOC_CTX *frame = talloc_stackframe();
268         struct netlogon_creds_cli_lck *lck;
269         NTSTATUS status;
270
271         status = netlogon_creds_cli_lck(
272                 creds_ctx, NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
273                 frame, &lck);
274         if (!NT_STATUS_IS_OK(status)) {
275                 DBG_WARNING("netlogon_creds_cli_lck failed: %s\n",
276                             nt_errstr(status));
277                 TALLOC_FREE(frame);
278                 return status;
279         }
280
281         status = rpccli_setup_netlogon_creds_locked(
282                 cli, transport, creds_ctx, force_reauth, cli_creds, NULL);
283
284         TALLOC_FREE(frame);
285
286         return status;
287 }
288
289 NTSTATUS rpccli_connect_netlogon(
290         struct cli_state *cli,
291         enum dcerpc_transport_t transport,
292         struct netlogon_creds_cli_context *creds_ctx,
293         bool force_reauth,
294         struct cli_credentials *trust_creds,
295         struct rpc_pipe_client **_rpccli)
296 {
297         TALLOC_CTX *frame = talloc_stackframe();
298         struct netlogon_creds_CredentialState *creds = NULL;
299         enum netlogon_creds_cli_lck_type lck_type;
300         enum netr_SchannelType sec_chan_type;
301         struct netlogon_creds_cli_lck *lck = NULL;
302         uint32_t negotiate_flags;
303         uint8_t found_session_key[16] = {0};
304         bool found_existing_creds = false;
305         bool do_serverauth;
306         struct rpc_pipe_client *rpccli;
307         NTSTATUS status;
308         bool retry = false;
309         const char *remote_name = NULL;
310         const struct sockaddr_storage *remote_sockaddr = NULL;
311
312         sec_chan_type = cli_credentials_get_secure_channel_type(trust_creds);
313         if (sec_chan_type == SEC_CHAN_NULL) {
314                 DBG_ERR("secure_channel_type gave SEC_CHAN_NULL\n");
315                 status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
316                 goto fail;
317         }
318
319 again:
320
321         /*
322          * See whether we can use existing netlogon_creds or
323          * whether we have to serverauthenticate.
324          */
325         status = netlogon_creds_cli_get(creds_ctx, frame, &creds);
326
327         if (NT_STATUS_IS_OK(status)) {
328                 bool cmp = mem_equal_const_time(found_session_key,
329                                                 creds->session_key,
330                                                 sizeof(found_session_key));
331                 found_existing_creds = !cmp;
332
333                 memcpy(found_session_key,
334                        creds->session_key,
335                        sizeof(found_session_key));
336
337                 TALLOC_FREE(creds);
338         }
339
340         lck_type = (force_reauth || !found_existing_creds) ?
341                 NETLOGON_CREDS_CLI_LCK_EXCLUSIVE :
342                 NETLOGON_CREDS_CLI_LCK_SHARED;
343
344         status = netlogon_creds_cli_lck(creds_ctx, lck_type, frame, &lck);
345         if (!NT_STATUS_IS_OK(status)) {
346                 DBG_DEBUG("netlogon_creds_cli_lck failed: %s\n",
347                           nt_errstr(status));
348                 goto fail;
349         }
350
351         if (!found_existing_creds) {
352                 /*
353                  * Try to find creds under the lock again. Someone
354                  * else might have done it for us.
355                  */
356                 status = netlogon_creds_cli_get(creds_ctx, frame, &creds);
357
358                 if (NT_STATUS_IS_OK(status)) {
359                         bool cmp = mem_equal_const_time(found_session_key,
360                                                         creds->session_key,
361                                                         sizeof(found_session_key));
362                         found_existing_creds = !cmp;
363
364                         memcpy(found_session_key, creds->session_key,
365                                sizeof(found_session_key));
366
367                         TALLOC_FREE(creds);
368                 }
369         }
370
371         remote_name = smbXcli_conn_remote_name(cli->conn);
372         remote_sockaddr = smbXcli_conn_remote_sockaddr(cli->conn);
373
374         do_serverauth = force_reauth || !found_existing_creds;
375
376         if (!do_serverauth) {
377                 /*
378                  * Do the quick schannel bind without a reauth
379                  */
380                 status = cli_rpc_pipe_open_bind_schannel(cli,
381                                                          &ndr_table_netlogon,
382                                                          transport,
383                                                          creds_ctx,
384                                                          remote_name,
385                                                          remote_sockaddr,
386                                                          &rpccli);
387                 if (!retry && NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
388                         DBG_DEBUG("Retrying with serverauthenticate\n");
389                         TALLOC_FREE(lck);
390                         retry = true;
391                         goto again;
392                 }
393                 if (!NT_STATUS_IS_OK(status)) {
394                         DBG_DEBUG("cli_rpc_pipe_open_bind_schannel "
395                                   "failed: %s\n", nt_errstr(status));
396                         goto fail;
397                 }
398                 goto done;
399         }
400
401         if (cli_credentials_is_anonymous(trust_creds)) {
402                 DBG_WARNING("get_trust_credential for %s only gave anonymous,"
403                             "unable to negotiate NETLOGON credentials\n",
404                             netlogon_creds_cli_debug_string(
405                                     creds_ctx, frame));
406                 status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
407                 goto fail;
408         }
409
410         status = rpccli_setup_netlogon_creds_locked(
411                 cli, transport, creds_ctx, true, trust_creds,
412                 &negotiate_flags);
413         if (!NT_STATUS_IS_OK(status)) {
414                 DBG_DEBUG("rpccli_setup_netlogon_creds failed for %s, "
415                           "unable to setup NETLOGON credentials: %s\n",
416                           netlogon_creds_cli_debug_string(
417                                   creds_ctx, frame),
418                           nt_errstr(status));
419                 goto fail;
420         }
421
422         if (!(negotiate_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
423                 if (lp_winbind_sealed_pipes() || lp_require_strong_key()) {
424                         status = NT_STATUS_DOWNGRADE_DETECTED;
425                         DBG_WARNING("Unwilling to make connection to %s"
426                                     "without connection level security, "
427                                     "must set 'winbind sealed pipes = false'"
428                                     " and 'require strong key = false' "
429                                     "to proceed: %s\n",
430                                     netlogon_creds_cli_debug_string(
431                                             creds_ctx, frame),
432                                     nt_errstr(status));
433                         goto fail;
434                 }
435
436                 status = cli_rpc_pipe_open_noauth_transport(cli,
437                                                             transport,
438                                                             &ndr_table_netlogon,
439                                                             remote_name,
440                                                             remote_sockaddr,
441                                                             &rpccli);
442                 if (!NT_STATUS_IS_OK(status)) {
443                         DBG_DEBUG("cli_rpc_pipe_open_noauth_transport "
444                                   "failed: %s\n", nt_errstr(status));
445                         goto fail;
446                 }
447                 goto done;
448         }
449
450         status = cli_rpc_pipe_open_bind_schannel(cli,
451                                                  &ndr_table_netlogon,
452                                                  transport,
453                                                  creds_ctx,
454                                                  remote_name,
455                                                  remote_sockaddr,
456                                                  &rpccli);
457         if (!NT_STATUS_IS_OK(status)) {
458                 DBG_DEBUG("cli_rpc_pipe_open_bind_schannel "
459                           "failed: %s\n", nt_errstr(status));
460                 goto fail;
461         }
462
463         status = netlogon_creds_cli_check(creds_ctx, rpccli->binding_handle,
464                                           NULL);
465         if (!NT_STATUS_IS_OK(status)) {
466                 DBG_WARNING("netlogon_creds_cli_check failed: %s\n",
467                             nt_errstr(status));
468                 goto fail;
469         }
470
471 done:
472         *_rpccli = rpccli;
473         status = NT_STATUS_OK;
474 fail:
475         ZERO_STRUCT(found_session_key);
476         TALLOC_FREE(lck);
477         TALLOC_FREE(frame);
478         return status;
479 }
480
481 /* Logon domain user */
482
483 NTSTATUS rpccli_netlogon_password_logon(
484         struct netlogon_creds_cli_context *creds_ctx,
485         struct dcerpc_binding_handle *binding_handle,
486         TALLOC_CTX *mem_ctx,
487         uint32_t logon_parameters,
488         const char *domain,
489         const char *username,
490         const char *password,
491         const char *workstation,
492         const uint64_t logon_id,
493         enum netr_LogonInfoClass logon_type,
494         uint8_t *authoritative,
495         uint32_t *flags,
496         uint16_t *_validation_level,
497         union netr_Validation **_validation)
498 {
499         TALLOC_CTX *frame = talloc_stackframe();
500         NTSTATUS status;
501         union netr_LogonLevel *logon;
502         uint16_t validation_level = 0;
503         union netr_Validation *validation = NULL;
504         char *workstation_slash = NULL;
505
506         unsigned char local_nt_response[24];
507         unsigned char local_lm_response[24];
508         struct samr_Password lmpassword = {.hash = {0}};
509         struct samr_Password ntpassword = {.hash = {0}};
510         struct netr_ChallengeResponse lm = {0};
511         struct netr_ChallengeResponse nt = {0};
512
513         logon = talloc_zero(frame, union netr_LogonLevel);
514         if (logon == NULL) {
515                 TALLOC_FREE(frame);
516                 return NT_STATUS_NO_MEMORY;
517         }
518
519         if (workstation == NULL) {
520                 workstation = lp_netbios_name();
521         }
522
523         workstation_slash = talloc_asprintf(frame, "\\\\%s", workstation);
524         if (workstation_slash == NULL) {
525                 TALLOC_FREE(frame);
526                 return NT_STATUS_NO_MEMORY;
527         }
528
529         /* Initialise input parameters */
530
531         switch (logon_type) {
532         case NetlogonInteractiveInformation:
533         case NetlogonInteractiveTransitiveInformation: {
534
535                 struct netr_PasswordInfo *password_info;
536
537
538                 password_info = talloc_zero(frame, struct netr_PasswordInfo);
539                 if (password_info == NULL) {
540                         TALLOC_FREE(frame);
541                         return NT_STATUS_NO_MEMORY;
542                 }
543
544                 nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash);
545
546                 password_info->identity_info.domain_name.string         = domain;
547                 password_info->identity_info.parameter_control          = logon_parameters;
548                 password_info->identity_info.logon_id                   = logon_id;
549                 password_info->identity_info.account_name.string        = username;
550                 password_info->identity_info.workstation.string         = workstation_slash;
551
552                 password_info->lmpassword = lmpassword;
553                 password_info->ntpassword = ntpassword;
554
555                 logon->password = password_info;
556
557                 break;
558         }
559         case NetlogonNetworkInformation:
560         case NetlogonNetworkTransitiveInformation: {
561                 struct netr_NetworkInfo *network_info;
562                 uint8_t chal[8];
563                 int rc;
564
565                 ZERO_STRUCT(lm);
566                 ZERO_STRUCT(nt);
567
568                 network_info = talloc_zero(frame, struct netr_NetworkInfo);
569                 if (network_info == NULL) {
570                         TALLOC_FREE(frame);
571                         return NT_STATUS_NO_MEMORY;
572                 }
573
574                 generate_random_buffer(chal, 8);
575
576                 SMBencrypt(password, chal, local_lm_response);
577                 rc = SMBNTencrypt(password, chal, local_nt_response);
578                 if (rc != 0) {
579                         TALLOC_FREE(frame);
580                         return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
581                 }
582
583                 lm.length = 24;
584                 lm.data = local_lm_response;
585
586                 nt.length = 24;
587                 nt.data = local_nt_response;
588
589                 network_info->identity_info.domain_name.string          = domain;
590                 network_info->identity_info.parameter_control           = logon_parameters;
591                 network_info->identity_info.logon_id                    = logon_id;
592                 network_info->identity_info.account_name.string         = username;
593                 network_info->identity_info.workstation.string          = workstation_slash;
594
595                 memcpy(network_info->challenge, chal, 8);
596                 network_info->nt = nt;
597                 network_info->lm = lm;
598
599                 logon->network = network_info;
600
601                 break;
602         }
603         default:
604                 DEBUG(0, ("switch value %d not supported\n",
605                         logon_type));
606                 TALLOC_FREE(frame);
607                 return NT_STATUS_INVALID_INFO_CLASS;
608         }
609
610         status = netlogon_creds_cli_LogonSamLogon(creds_ctx,
611                                                   binding_handle,
612                                                   logon_type,
613                                                   logon,
614                                                   mem_ctx,
615                                                   &validation_level,
616                                                   &validation,
617                                                   authoritative,
618                                                   flags);
619         if (!NT_STATUS_IS_OK(status)) {
620                 TALLOC_FREE(frame);
621                 return status;
622         }
623
624         TALLOC_FREE(frame);
625         *_validation_level = validation_level;
626         *_validation = validation;
627
628         return NT_STATUS_OK;
629 }
630
631 /**
632  * Logon domain user with an 'network' SAM logon
633  *
634  * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
635  **/
636
637
638 NTSTATUS rpccli_netlogon_network_logon(
639         struct netlogon_creds_cli_context *creds_ctx,
640         struct dcerpc_binding_handle *binding_handle,
641         TALLOC_CTX *mem_ctx,
642         uint32_t logon_parameters,
643         const char *username,
644         const char *domain,
645         const char *workstation,
646         const uint64_t logon_id,
647         DATA_BLOB chal,
648         DATA_BLOB lm_response,
649         DATA_BLOB nt_response,
650         enum netr_LogonInfoClass logon_type,
651         uint8_t *authoritative,
652         uint32_t *flags,
653         uint16_t *_validation_level,
654         union netr_Validation **_validation)
655 {
656         NTSTATUS status;
657         const char *workstation_name_slash;
658         union netr_LogonLevel *logon = NULL;
659         struct netr_NetworkInfo *network_info;
660         uint16_t validation_level = 0;
661         union netr_Validation *validation = NULL;
662         struct netr_ChallengeResponse lm;
663         struct netr_ChallengeResponse nt;
664
665         *_validation = NULL;
666
667         ZERO_STRUCT(lm);
668         ZERO_STRUCT(nt);
669
670         switch (logon_type) {
671         case NetlogonNetworkInformation:
672         case NetlogonNetworkTransitiveInformation:
673                 break;
674         default:
675                 DEBUG(0, ("switch value %d not supported\n",
676                         logon_type));
677                 return NT_STATUS_INVALID_INFO_CLASS;
678         }
679
680         logon = talloc_zero(mem_ctx, union netr_LogonLevel);
681         if (!logon) {
682                 return NT_STATUS_NO_MEMORY;
683         }
684
685         network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo);
686         if (!network_info) {
687                 return NT_STATUS_NO_MEMORY;
688         }
689
690         if (workstation == NULL) {
691                 workstation = lp_netbios_name();
692         }
693
694         if (workstation[0] != '\\' && workstation[1] != '\\') {
695                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
696         } else {
697                 workstation_name_slash = workstation;
698         }
699
700         if (!workstation_name_slash) {
701                 DEBUG(0, ("talloc_asprintf failed!\n"));
702                 return NT_STATUS_NO_MEMORY;
703         }
704
705         /* Initialise input parameters */
706
707         lm.data = lm_response.data;
708         lm.length = lm_response.length;
709         nt.data = nt_response.data;
710         nt.length = nt_response.length;
711
712         network_info->identity_info.domain_name.string          = domain;
713         network_info->identity_info.parameter_control           = logon_parameters;
714         network_info->identity_info.logon_id                    = logon_id;
715         network_info->identity_info.account_name.string         = username;
716         network_info->identity_info.workstation.string          = workstation_name_slash;
717
718         if (chal.length != 8) {
719                 DBG_WARNING("Invalid challenge length %zd\n", chal.length);
720                 return NT_STATUS_INVALID_PARAMETER;
721         }
722
723         memcpy(network_info->challenge, chal.data, chal.length);
724         network_info->nt = nt;
725         network_info->lm = lm;
726
727         logon->network = network_info;
728
729         /* Marshall data and send request */
730
731         status = netlogon_creds_cli_LogonSamLogon(creds_ctx,
732                                                   binding_handle,
733                                                   logon_type,
734                                                   logon,
735                                                   mem_ctx,
736                                                   &validation_level,
737                                                   &validation,
738                                                   authoritative,
739                                                   flags);
740         if (!NT_STATUS_IS_OK(status)) {
741                 return status;
742         }
743
744         *_validation_level = validation_level;
745         *_validation = validation;
746
747         return NT_STATUS_OK;
748 }
749
750 NTSTATUS rpccli_netlogon_interactive_logon(
751         struct netlogon_creds_cli_context *creds_ctx,
752         struct dcerpc_binding_handle *binding_handle,
753         TALLOC_CTX *mem_ctx,
754         uint32_t logon_parameters,
755         const char *username,
756         const char *domain,
757         const char *workstation,
758         const uint64_t logon_id,
759         DATA_BLOB lm_hash,
760         DATA_BLOB nt_hash,
761         enum netr_LogonInfoClass logon_type,
762         uint8_t *authoritative,
763         uint32_t *flags,
764         uint16_t *_validation_level,
765         union netr_Validation **_validation)
766 {
767         TALLOC_CTX *frame = talloc_stackframe();
768         NTSTATUS status;
769         const char *workstation_name_slash;
770         union netr_LogonLevel *logon = NULL;
771         struct netr_PasswordInfo *password_info = NULL;
772         uint16_t validation_level = 0;
773         union netr_Validation *validation = NULL;
774         struct netr_ChallengeResponse lm;
775         struct netr_ChallengeResponse nt;
776
777         *_validation = NULL;
778
779         ZERO_STRUCT(lm);
780         ZERO_STRUCT(nt);
781
782         switch (logon_type) {
783         case NetlogonInteractiveInformation:
784         case NetlogonInteractiveTransitiveInformation:
785                 break;
786         default:
787                 DEBUG(0, ("switch value %d not supported\n",
788                         logon_type));
789                 TALLOC_FREE(frame);
790                 return NT_STATUS_INVALID_INFO_CLASS;
791         }
792
793         logon = talloc_zero(mem_ctx, union netr_LogonLevel);
794         if (logon == NULL) {
795                 TALLOC_FREE(frame);
796                 return NT_STATUS_NO_MEMORY;
797         }
798
799         password_info = talloc_zero(logon, struct netr_PasswordInfo);
800         if (password_info == NULL) {
801                 TALLOC_FREE(frame);
802                 return NT_STATUS_NO_MEMORY;
803         }
804
805         if (workstation[0] != '\\' && workstation[1] != '\\') {
806                 workstation_name_slash = talloc_asprintf(frame, "\\\\%s", workstation);
807         } else {
808                 workstation_name_slash = workstation;
809         }
810
811         if (workstation_name_slash == NULL) {
812                 TALLOC_FREE(frame);
813                 return NT_STATUS_NO_MEMORY;
814         }
815
816         /* Initialise input parameters */
817
818         password_info->identity_info.domain_name.string         = domain;
819         password_info->identity_info.parameter_control          = logon_parameters;
820         password_info->identity_info.logon_id                   = logon_id;
821         password_info->identity_info.account_name.string        = username;
822         password_info->identity_info.workstation.string         = workstation_name_slash;
823
824         if (nt_hash.length != sizeof(password_info->ntpassword.hash)) {
825                 TALLOC_FREE(frame);
826                 return NT_STATUS_INVALID_PARAMETER;
827         }
828         memcpy(password_info->ntpassword.hash, nt_hash.data, nt_hash.length);
829         if (lm_hash.length != 0) {
830                 if (lm_hash.length != sizeof(password_info->lmpassword.hash)) {
831                         TALLOC_FREE(frame);
832                         return NT_STATUS_INVALID_PARAMETER;
833                 }
834                 memcpy(password_info->lmpassword.hash, lm_hash.data, lm_hash.length);
835         }
836
837         logon->password = password_info;
838
839         /* Marshall data and send request */
840
841         status = netlogon_creds_cli_LogonSamLogon(creds_ctx,
842                                                   binding_handle,
843                                                   logon_type,
844                                                   logon,
845                                                   mem_ctx,
846                                                   &validation_level,
847                                                   &validation,
848                                                   authoritative,
849                                                   flags);
850         if (!NT_STATUS_IS_OK(status)) {
851                 TALLOC_FREE(frame);
852                 return status;
853         }
854
855         *_validation_level = validation_level;
856         *_validation = validation;
857
858         TALLOC_FREE(frame);
859         return NT_STATUS_OK;
860 }