cli_netlogon: Eliminate rpccli_setup_netlogon_creds_with_creds
[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/init_netlogon.h"
34 #include "rpc_client/util_netlogon.h"
35 #include "../libcli/security/security.h"
36 #include "lib/param/param.h"
37 #include "libcli/smb/smbXcli_base.h"
38 #include "dbwrap/dbwrap.h"
39 #include "dbwrap/dbwrap_open.h"
40 #include "util_tdb.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(&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 **netlogon_creds)
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         if (sec_chan_type == SEC_CHAN_NULL) {
144                 return NT_STATUS_INVALID_PARAMETER_MIX;
145         }
146
147         client_account = cli_credentials_get_username(creds);
148         server_netbios_domain = cli_credentials_get_domain(creds);
149         server_dns_domain = cli_credentials_get_realm(creds);
150
151         return rpccli_create_netlogon_creds(server_computer,
152                                             server_netbios_domain,
153                                             server_dns_domain,
154                                             client_account,
155                                             sec_chan_type,
156                                             msg_ctx, mem_ctx,
157                                             netlogon_creds);
158 }
159
160 NTSTATUS rpccli_setup_netlogon_creds(
161         struct cli_state *cli,
162         enum dcerpc_transport_t transport,
163         struct netlogon_creds_cli_context *netlogon_creds,
164         bool force_reauth,
165         struct cli_credentials *cli_creds)
166 {
167         TALLOC_CTX *frame = talloc_stackframe();
168         struct rpc_pipe_client *netlogon_pipe = NULL;
169         struct netlogon_creds_CredentialState *creds = NULL;
170         uint8_t num_nt_hashes = 0;
171         const struct samr_Password *nt_hashes[2] = { NULL, NULL };
172         uint8_t idx_nt_hashes = 0;
173         NTSTATUS status;
174
175         status = netlogon_creds_cli_get(netlogon_creds,
176                                         frame, &creds);
177         if (NT_STATUS_IS_OK(status)) {
178                 const char *action = "using";
179
180                 if (force_reauth) {
181                         action = "overwrite";
182                 }
183
184                 DEBUG(5,("%s: %s cached netlogon_creds cli[%s/%s] to %s\n",
185                          __FUNCTION__, action,
186                          creds->account_name, creds->computer_name,
187                          smbXcli_conn_remote_name(cli->conn)));
188                 if (!force_reauth) {
189                         TALLOC_FREE(frame);
190                         return NT_STATUS_OK;
191                 }
192                 TALLOC_FREE(creds);
193         }
194
195         nt_hashes[0] = cli_credentials_get_nt_hash(cli_creds, talloc_tos());
196         if (nt_hashes[0] == NULL) {
197                 TALLOC_FREE(frame);
198                 return NT_STATUS_NO_MEMORY;
199         }
200         num_nt_hashes = 1;
201
202         nt_hashes[1] = cli_credentials_get_old_nt_hash(cli_creds,
203                                                        talloc_tos());
204         if (nt_hashes[1] != NULL) {
205                 num_nt_hashes = 2;
206         }
207
208         status = cli_rpc_pipe_open_noauth_transport(cli,
209                                                     transport,
210                                                     &ndr_table_netlogon,
211                                                     &netlogon_pipe);
212         if (!NT_STATUS_IS_OK(status)) {
213                 DEBUG(5,("%s: failed to open noauth netlogon connection to %s - %s\n",
214                          __FUNCTION__,
215                          smbXcli_conn_remote_name(cli->conn),
216                          nt_errstr(status)));
217                 TALLOC_FREE(frame);
218                 return status;
219         }
220         talloc_steal(frame, netlogon_pipe);
221
222         status = netlogon_creds_cli_auth(netlogon_creds,
223                                          netlogon_pipe->binding_handle,
224                                          num_nt_hashes,
225                                          nt_hashes,
226                                          &idx_nt_hashes);
227         if (!NT_STATUS_IS_OK(status)) {
228                 TALLOC_FREE(frame);
229                 return status;
230         }
231
232         status = netlogon_creds_cli_get(netlogon_creds,
233                                         frame, &creds);
234         if (!NT_STATUS_IS_OK(status)) {
235                 TALLOC_FREE(frame);
236                 return NT_STATUS_INTERNAL_ERROR;
237         }
238
239         DEBUG(5,("%s: using new netlogon_creds cli[%s/%s] to %s\n",
240                  __FUNCTION__,
241                  creds->account_name, creds->computer_name,
242                  smbXcli_conn_remote_name(cli->conn)));
243
244         TALLOC_FREE(frame);
245         return NT_STATUS_OK;
246 }
247
248 static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
249                                         uint16_t validation_level,
250                                         union netr_Validation *validation,
251                                         struct netr_SamInfo3 **info3_p)
252 {
253         struct netr_SamInfo3 *info3;
254         NTSTATUS status;
255
256         if (validation == NULL) {
257                 return NT_STATUS_INVALID_PARAMETER;
258         }
259
260         switch (validation_level) {
261         case 3:
262                 if (validation->sam3 == NULL) {
263                         return NT_STATUS_INVALID_PARAMETER;
264                 }
265
266                 info3 = talloc_move(mem_ctx, &validation->sam3);
267                 break;
268         case 6:
269                 if (validation->sam6 == NULL) {
270                         return NT_STATUS_INVALID_PARAMETER;
271                 }
272
273                 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
274                 if (info3 == NULL) {
275                         return NT_STATUS_NO_MEMORY;
276                 }
277                 status = copy_netr_SamBaseInfo(info3, &validation->sam6->base, &info3->base);
278                 if (!NT_STATUS_IS_OK(status)) {
279                         TALLOC_FREE(info3);
280                         return status;
281                 }
282
283                 info3->sidcount = validation->sam6->sidcount;
284                 info3->sids = talloc_move(info3, &validation->sam6->sids);
285                 break;
286         default:
287                 return NT_STATUS_BAD_VALIDATION_CLASS;
288         }
289
290         *info3_p = info3;
291
292         return NT_STATUS_OK;
293 }
294
295 /* Logon domain user */
296
297 NTSTATUS rpccli_netlogon_password_logon(struct netlogon_creds_cli_context *creds,
298                                         struct dcerpc_binding_handle *binding_handle,
299                                         TALLOC_CTX *mem_ctx,
300                                         uint32_t logon_parameters,
301                                         const char *domain,
302                                         const char *username,
303                                         const char *password,
304                                         const char *workstation,
305                                         enum netr_LogonInfoClass logon_type,
306                                         uint8_t *authoritative,
307                                         uint32_t *flags,
308                                         struct netr_SamInfo3 **info3)
309 {
310         TALLOC_CTX *frame = talloc_stackframe();
311         NTSTATUS status;
312         union netr_LogonLevel *logon;
313         uint16_t validation_level = 0;
314         union netr_Validation *validation = NULL;
315         char *workstation_slash = NULL;
316
317         logon = talloc_zero(frame, union netr_LogonLevel);
318         if (logon == NULL) {
319                 TALLOC_FREE(frame);
320                 return NT_STATUS_NO_MEMORY;
321         }
322
323         if (workstation == NULL) {
324                 workstation = lp_netbios_name();
325         }
326
327         workstation_slash = talloc_asprintf(frame, "\\\\%s", workstation);
328         if (workstation_slash == NULL) {
329                 TALLOC_FREE(frame);
330                 return NT_STATUS_NO_MEMORY;
331         }
332
333         /* Initialise input parameters */
334
335         switch (logon_type) {
336         case NetlogonInteractiveInformation: {
337
338                 struct netr_PasswordInfo *password_info;
339
340                 struct samr_Password lmpassword;
341                 struct samr_Password ntpassword;
342
343                 password_info = talloc_zero(frame, struct netr_PasswordInfo);
344                 if (password_info == NULL) {
345                         TALLOC_FREE(frame);
346                         return NT_STATUS_NO_MEMORY;
347                 }
348
349                 nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash);
350
351                 password_info->identity_info.domain_name.string         = domain;
352                 password_info->identity_info.parameter_control          = logon_parameters;
353                 password_info->identity_info.logon_id_low               = 0xdead;
354                 password_info->identity_info.logon_id_high              = 0xbeef;
355                 password_info->identity_info.account_name.string        = username;
356                 password_info->identity_info.workstation.string         = workstation_slash;
357
358                 password_info->lmpassword = lmpassword;
359                 password_info->ntpassword = ntpassword;
360
361                 logon->password = password_info;
362
363                 break;
364         }
365         case NetlogonNetworkInformation: {
366                 struct netr_NetworkInfo *network_info;
367                 uint8_t chal[8];
368                 unsigned char local_lm_response[24];
369                 unsigned char local_nt_response[24];
370                 struct netr_ChallengeResponse lm;
371                 struct netr_ChallengeResponse nt;
372
373                 ZERO_STRUCT(lm);
374                 ZERO_STRUCT(nt);
375
376                 network_info = talloc_zero(frame, struct netr_NetworkInfo);
377                 if (network_info == NULL) {
378                         TALLOC_FREE(frame);
379                         return NT_STATUS_NO_MEMORY;
380                 }
381
382                 generate_random_buffer(chal, 8);
383
384                 SMBencrypt(password, chal, local_lm_response);
385                 SMBNTencrypt(password, chal, local_nt_response);
386
387                 lm.length = 24;
388                 lm.data = local_lm_response;
389
390                 nt.length = 24;
391                 nt.data = local_nt_response;
392
393                 network_info->identity_info.domain_name.string          = domain;
394                 network_info->identity_info.parameter_control           = logon_parameters;
395                 network_info->identity_info.logon_id_low                = 0xdead;
396                 network_info->identity_info.logon_id_high               = 0xbeef;
397                 network_info->identity_info.account_name.string         = username;
398                 network_info->identity_info.workstation.string          = workstation_slash;
399
400                 memcpy(network_info->challenge, chal, 8);
401                 network_info->nt = nt;
402                 network_info->lm = lm;
403
404                 logon->network = network_info;
405
406                 break;
407         }
408         default:
409                 DEBUG(0, ("switch value %d not supported\n",
410                         logon_type));
411                 TALLOC_FREE(frame);
412                 return NT_STATUS_INVALID_INFO_CLASS;
413         }
414
415         status = netlogon_creds_cli_LogonSamLogon(creds,
416                                                   binding_handle,
417                                                   logon_type,
418                                                   logon,
419                                                   frame,
420                                                   &validation_level,
421                                                   &validation,
422                                                   authoritative,
423                                                   flags);
424         if (!NT_STATUS_IS_OK(status)) {
425                 TALLOC_FREE(frame);
426                 return status;
427         }
428
429         status = map_validation_to_info3(mem_ctx,
430                                          validation_level, validation,
431                                          info3);
432         TALLOC_FREE(frame);
433         if (!NT_STATUS_IS_OK(status)) {
434                 return status;
435         }
436
437
438         return NT_STATUS_OK;
439 }
440
441 /**
442  * Logon domain user with an 'network' SAM logon
443  *
444  * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
445  **/
446
447
448 NTSTATUS rpccli_netlogon_network_logon(struct netlogon_creds_cli_context *creds,
449                                        struct dcerpc_binding_handle *binding_handle,
450                                        TALLOC_CTX *mem_ctx,
451                                        uint32_t logon_parameters,
452                                        const char *username,
453                                        const char *domain,
454                                        const char *workstation,
455                                        const uint8_t chal[8],
456                                        DATA_BLOB lm_response,
457                                        DATA_BLOB nt_response,
458                                        uint8_t *authoritative,
459                                        uint32_t *flags,
460                                        struct netr_SamInfo3 **info3)
461 {
462         NTSTATUS status;
463         const char *workstation_name_slash;
464         union netr_LogonLevel *logon = NULL;
465         struct netr_NetworkInfo *network_info;
466         uint16_t validation_level = 0;
467         union netr_Validation *validation = NULL;
468         struct netr_ChallengeResponse lm;
469         struct netr_ChallengeResponse nt;
470
471         *info3 = NULL;
472
473         ZERO_STRUCT(lm);
474         ZERO_STRUCT(nt);
475
476         logon = talloc_zero(mem_ctx, union netr_LogonLevel);
477         if (!logon) {
478                 return NT_STATUS_NO_MEMORY;
479         }
480
481         network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo);
482         if (!network_info) {
483                 return NT_STATUS_NO_MEMORY;
484         }
485
486         if (workstation[0] != '\\' && workstation[1] != '\\') {
487                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
488         } else {
489                 workstation_name_slash = workstation;
490         }
491
492         if (!workstation_name_slash) {
493                 DEBUG(0, ("talloc_asprintf failed!\n"));
494                 return NT_STATUS_NO_MEMORY;
495         }
496
497         /* Initialise input parameters */
498
499         lm.data = lm_response.data;
500         lm.length = lm_response.length;
501         nt.data = nt_response.data;
502         nt.length = nt_response.length;
503
504         network_info->identity_info.domain_name.string          = domain;
505         network_info->identity_info.parameter_control           = logon_parameters;
506         network_info->identity_info.logon_id_low                = 0xdead;
507         network_info->identity_info.logon_id_high               = 0xbeef;
508         network_info->identity_info.account_name.string         = username;
509         network_info->identity_info.workstation.string          = workstation_name_slash;
510
511         memcpy(network_info->challenge, chal, 8);
512         network_info->nt = nt;
513         network_info->lm = lm;
514
515         logon->network = network_info;
516
517         /* Marshall data and send request */
518
519         status = netlogon_creds_cli_LogonSamLogon(creds,
520                                                   binding_handle,
521                                                   NetlogonNetworkInformation,
522                                                   logon,
523                                                   mem_ctx,
524                                                   &validation_level,
525                                                   &validation,
526                                                   authoritative,
527                                                   flags);
528         if (!NT_STATUS_IS_OK(status)) {
529                 return status;
530         }
531
532         status = map_validation_to_info3(mem_ctx,
533                                          validation_level, validation,
534                                          info3);
535         if (!NT_STATUS_IS_OK(status)) {
536                 return status;
537         }
538
539         return NT_STATUS_OK;
540 }