a5ea02cfa8429975a0669d14ba8344696b98bc2a
[obnox/samba/samba-obnox.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(talloc_autofree_context(), 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 NTSTATUS rpccli_create_netlogon_creds(const char *server_computer,
90                                       const char *server_netbios_domain,
91                                       const char *client_account,
92                                       enum netr_SchannelType sec_chan_type,
93                                       struct messaging_context *msg_ctx,
94                                       TALLOC_CTX *mem_ctx,
95                                       struct netlogon_creds_cli_context **netlogon_creds)
96 {
97         TALLOC_CTX *frame = talloc_stackframe();
98         struct loadparm_context *lp_ctx;
99         NTSTATUS status;
100
101         status = rpccli_pre_open_netlogon_creds();
102         if (!NT_STATUS_IS_OK(status)) {
103                 TALLOC_FREE(frame);
104                 return status;
105         }
106
107         lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
108         if (lp_ctx == NULL) {
109                 TALLOC_FREE(frame);
110                 return NT_STATUS_NO_MEMORY;
111         }
112         status = netlogon_creds_cli_context_global(lp_ctx,
113                                                    msg_ctx,
114                                                    client_account,
115                                                    sec_chan_type,
116                                                    server_computer,
117                                                    server_netbios_domain,
118                                                    mem_ctx, netlogon_creds);
119         TALLOC_FREE(frame);
120         if (!NT_STATUS_IS_OK(status)) {
121                 return status;
122         }
123
124         return NT_STATUS_OK;
125 }
126
127 NTSTATUS rpccli_setup_netlogon_creds(struct cli_state *cli,
128                                      enum dcerpc_transport_t transport,
129                                      struct netlogon_creds_cli_context *netlogon_creds,
130                                      bool force_reauth,
131                                      struct samr_Password current_nt_hash,
132                                      const struct samr_Password *previous_nt_hash)
133 {
134         TALLOC_CTX *frame = talloc_stackframe();
135         struct rpc_pipe_client *netlogon_pipe = NULL;
136         struct netlogon_creds_CredentialState *creds = NULL;
137         NTSTATUS status;
138
139         status = netlogon_creds_cli_get(netlogon_creds,
140                                         frame, &creds);
141         if (NT_STATUS_IS_OK(status)) {
142                 const char *action = "using";
143
144                 if (force_reauth) {
145                         action = "overwrite";
146                 }
147
148                 DEBUG(5,("%s: %s cached netlogon_creds cli[%s/%s] to %s\n",
149                          __FUNCTION__, action,
150                          creds->account_name, creds->computer_name,
151                          smbXcli_conn_remote_name(cli->conn)));
152                 if (!force_reauth) {
153                         TALLOC_FREE(frame);
154                         return NT_STATUS_OK;
155                 }
156                 TALLOC_FREE(creds);
157         }
158
159         status = cli_rpc_pipe_open_noauth_transport(cli,
160                                                     transport,
161                                                     &ndr_table_netlogon,
162                                                     &netlogon_pipe);
163         if (!NT_STATUS_IS_OK(status)) {
164                 DEBUG(5,("%s: failed to open noauth netlogon connection to %s - %s\n",
165                          __FUNCTION__,
166                          smbXcli_conn_remote_name(cli->conn),
167                          nt_errstr(status)));
168                 TALLOC_FREE(frame);
169                 return status;
170         }
171         talloc_steal(frame, netlogon_pipe);
172
173         status = netlogon_creds_cli_auth(netlogon_creds,
174                                          netlogon_pipe->binding_handle,
175                                          current_nt_hash,
176                                          previous_nt_hash);
177         if (!NT_STATUS_IS_OK(status)) {
178                 TALLOC_FREE(frame);
179                 return status;
180         }
181
182         status = netlogon_creds_cli_get(netlogon_creds,
183                                         frame, &creds);
184         if (!NT_STATUS_IS_OK(status)) {
185                 TALLOC_FREE(frame);
186                 return NT_STATUS_INTERNAL_ERROR;
187         }
188
189         DEBUG(5,("%s: using new netlogon_creds cli[%s/%s] to %s\n",
190                  __FUNCTION__,
191                  creds->account_name, creds->computer_name,
192                  smbXcli_conn_remote_name(cli->conn)));
193
194         TALLOC_FREE(frame);
195         return NT_STATUS_OK;
196 }
197
198 static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
199                                         uint16_t validation_level,
200                                         union netr_Validation *validation,
201                                         struct netr_SamInfo3 **info3_p)
202 {
203         struct netr_SamInfo3 *info3;
204         NTSTATUS status;
205
206         if (validation == NULL) {
207                 return NT_STATUS_INVALID_PARAMETER;
208         }
209
210         switch (validation_level) {
211         case 3:
212                 if (validation->sam3 == NULL) {
213                         return NT_STATUS_INVALID_PARAMETER;
214                 }
215
216                 info3 = talloc_move(mem_ctx, &validation->sam3);
217                 break;
218         case 6:
219                 if (validation->sam6 == NULL) {
220                         return NT_STATUS_INVALID_PARAMETER;
221                 }
222
223                 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
224                 if (info3 == NULL) {
225                         return NT_STATUS_NO_MEMORY;
226                 }
227                 status = copy_netr_SamBaseInfo(info3, &validation->sam6->base, &info3->base);
228                 if (!NT_STATUS_IS_OK(status)) {
229                         TALLOC_FREE(info3);
230                         return status;
231                 }
232
233                 info3->sidcount = validation->sam6->sidcount;
234                 info3->sids = talloc_move(info3, &validation->sam6->sids);
235                 break;
236         default:
237                 return NT_STATUS_BAD_VALIDATION_CLASS;
238         }
239
240         *info3_p = info3;
241
242         return NT_STATUS_OK;
243 }
244
245 /* Logon domain user */
246
247 NTSTATUS rpccli_netlogon_password_logon(struct netlogon_creds_cli_context *creds,
248                                         struct dcerpc_binding_handle *binding_handle,
249                                         TALLOC_CTX *mem_ctx,
250                                         uint32_t logon_parameters,
251                                         const char *domain,
252                                         const char *username,
253                                         const char *password,
254                                         const char *workstation,
255                                         enum netr_LogonInfoClass logon_type,
256                                         struct netr_SamInfo3 **info3)
257 {
258         TALLOC_CTX *frame = talloc_stackframe();
259         NTSTATUS status;
260         union netr_LogonLevel *logon;
261         uint16_t validation_level = 0;
262         union netr_Validation *validation = NULL;
263         uint8_t authoritative = 0;
264         uint32_t flags = 0;
265         char *workstation_slash = NULL;
266
267         logon = talloc_zero(frame, union netr_LogonLevel);
268         if (logon == NULL) {
269                 TALLOC_FREE(frame);
270                 return NT_STATUS_NO_MEMORY;
271         }
272
273         if (workstation == NULL) {
274                 workstation = lp_netbios_name();
275         }
276
277         workstation_slash = talloc_asprintf(frame, "\\\\%s", workstation);
278         if (workstation_slash == NULL) {
279                 TALLOC_FREE(frame);
280                 return NT_STATUS_NO_MEMORY;
281         }
282
283         /* Initialise input parameters */
284
285         switch (logon_type) {
286         case NetlogonInteractiveInformation: {
287
288                 struct netr_PasswordInfo *password_info;
289
290                 struct samr_Password lmpassword;
291                 struct samr_Password ntpassword;
292
293                 password_info = talloc_zero(frame, struct netr_PasswordInfo);
294                 if (password_info == NULL) {
295                         TALLOC_FREE(frame);
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         = workstation_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(frame, struct netr_NetworkInfo);
327                 if (network_info == NULL) {
328                         TALLOC_FREE(frame);
329                         return NT_STATUS_NO_MEMORY;
330                 }
331
332                 generate_random_buffer(chal, 8);
333
334                 SMBencrypt(password, chal, local_lm_response);
335                 SMBNTencrypt(password, chal, local_nt_response);
336
337                 lm.length = 24;
338                 lm.data = local_lm_response;
339
340                 nt.length = 24;
341                 nt.data = local_nt_response;
342
343                 network_info->identity_info.domain_name.string          = domain;
344                 network_info->identity_info.parameter_control           = logon_parameters;
345                 network_info->identity_info.logon_id_low                = 0xdead;
346                 network_info->identity_info.logon_id_high               = 0xbeef;
347                 network_info->identity_info.account_name.string         = username;
348                 network_info->identity_info.workstation.string          = workstation_slash;
349
350                 memcpy(network_info->challenge, chal, 8);
351                 network_info->nt = nt;
352                 network_info->lm = lm;
353
354                 logon->network = network_info;
355
356                 break;
357         }
358         default:
359                 DEBUG(0, ("switch value %d not supported\n",
360                         logon_type));
361                 TALLOC_FREE(frame);
362                 return NT_STATUS_INVALID_INFO_CLASS;
363         }
364
365         status = netlogon_creds_cli_LogonSamLogon(creds,
366                                                   binding_handle,
367                                                   logon_type,
368                                                   logon,
369                                                   frame,
370                                                   &validation_level,
371                                                   &validation,
372                                                   &authoritative,
373                                                   &flags);
374         if (!NT_STATUS_IS_OK(status)) {
375                 TALLOC_FREE(frame);
376                 return status;
377         }
378
379         status = map_validation_to_info3(mem_ctx,
380                                          validation_level, validation,
381                                          info3);
382         TALLOC_FREE(frame);
383         if (!NT_STATUS_IS_OK(status)) {
384                 return status;
385         }
386
387
388         return NT_STATUS_OK;
389 }
390
391 /**
392  * Logon domain user with an 'network' SAM logon
393  *
394  * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
395  **/
396
397
398 NTSTATUS rpccli_netlogon_network_logon(struct netlogon_creds_cli_context *creds,
399                                        struct dcerpc_binding_handle *binding_handle,
400                                        TALLOC_CTX *mem_ctx,
401                                        uint32_t logon_parameters,
402                                        const char *username,
403                                        const char *domain,
404                                        const char *workstation,
405                                        const uint8 chal[8],
406                                        DATA_BLOB lm_response,
407                                        DATA_BLOB nt_response,
408                                        uint8_t *authoritative,
409                                        uint32_t *flags,
410                                        struct netr_SamInfo3 **info3)
411 {
412         NTSTATUS status;
413         const char *workstation_name_slash;
414         union netr_LogonLevel *logon = NULL;
415         struct netr_NetworkInfo *network_info;
416         uint16_t validation_level = 0;
417         union netr_Validation *validation = NULL;
418         uint8_t _authoritative = 0;
419         uint32_t _flags = 0;
420         struct netr_ChallengeResponse lm;
421         struct netr_ChallengeResponse nt;
422
423         *info3 = NULL;
424
425         if (authoritative == NULL) {
426                 authoritative = &_authoritative;
427         }
428         if (flags == NULL) {
429                 flags = &_flags;
430         }
431
432         ZERO_STRUCT(lm);
433         ZERO_STRUCT(nt);
434
435         logon = talloc_zero(mem_ctx, union netr_LogonLevel);
436         if (!logon) {
437                 return NT_STATUS_NO_MEMORY;
438         }
439
440         network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo);
441         if (!network_info) {
442                 return NT_STATUS_NO_MEMORY;
443         }
444
445         if (workstation[0] != '\\' && workstation[1] != '\\') {
446                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
447         } else {
448                 workstation_name_slash = workstation;
449         }
450
451         if (!workstation_name_slash) {
452                 DEBUG(0, ("talloc_asprintf failed!\n"));
453                 return NT_STATUS_NO_MEMORY;
454         }
455
456         /* Initialise input parameters */
457
458         lm.data = lm_response.data;
459         lm.length = lm_response.length;
460         nt.data = nt_response.data;
461         nt.length = nt_response.length;
462
463         network_info->identity_info.domain_name.string          = domain;
464         network_info->identity_info.parameter_control           = logon_parameters;
465         network_info->identity_info.logon_id_low                = 0xdead;
466         network_info->identity_info.logon_id_high               = 0xbeef;
467         network_info->identity_info.account_name.string         = username;
468         network_info->identity_info.workstation.string          = workstation_name_slash;
469
470         memcpy(network_info->challenge, chal, 8);
471         network_info->nt = nt;
472         network_info->lm = lm;
473
474         logon->network = network_info;
475
476         /* Marshall data and send request */
477
478         status = netlogon_creds_cli_LogonSamLogon(creds,
479                                                   binding_handle,
480                                                   NetlogonNetworkInformation,
481                                                   logon,
482                                                   mem_ctx,
483                                                   &validation_level,
484                                                   &validation,
485                                                   authoritative,
486                                                   flags);
487         if (!NT_STATUS_IS_OK(status)) {
488                 return status;
489         }
490
491         status = map_validation_to_info3(mem_ctx,
492                                          validation_level, validation,
493                                          info3);
494         if (!NT_STATUS_IS_OK(status)) {
495                 return status;
496         }
497
498         return NT_STATUS_OK;
499 }