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