1 /*
2    Unix SMB/CIFS implementation.
3 
4    module to store/fetch session keys for the schannel client
5 
6    Copyright (C) Stefan Metzmacher 2013
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include <tevent.h>
25 #include "lib/util/tevent_ntstatus.h"
26 #include "lib/dbwrap/dbwrap.h"
27 #include "lib/dbwrap/dbwrap_rbt.h"
28 #include "lib/util/util_tdb.h"
29 #include "libcli/security/security.h"
30 #include "../lib/param/param.h"
31 #include "../libcli/auth/schannel.h"
32 #include "../librpc/gen_ndr/ndr_schannel.h"
33 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
34 #include "../librpc/gen_ndr/ndr_netlogon.h"
35 #include "../librpc/gen_ndr/server_id.h"
36 #include "netlogon_creds_cli.h"
37 #include "source3/include/messages.h"
38 #include "source3/include/g_lock.h"
39 #include "libds/common/roles.h"
40 #include "lib/crypto/md4.h"
41 #include "auth/credentials/credentials.h"
42 
43 struct netlogon_creds_cli_locked_state;
44 
45 struct netlogon_creds_cli_context {
46 	struct {
47 		const char *computer;
48 		const char *account;
49 		uint32_t proposed_flags;
50 		uint32_t required_flags;
51 		enum netr_SchannelType type;
52 		enum dcerpc_AuthLevel auth_level;
53 	} client;
54 
55 	struct {
56 		const char *computer;
57 		const char *netbios_domain;
58 		const char *dns_domain;
59 		uint32_t cached_flags;
60 		bool try_validation6;
61 		bool try_logon_ex;
62 		bool try_logon_with;
63 	} server;
64 
65 	struct {
66 		const char *key_name;
67 		TDB_DATA key_data;
68 		struct db_context *ctx;
69 		struct g_lock_ctx *g_ctx;
70 		struct netlogon_creds_cli_locked_state *locked_state;
71 		enum netlogon_creds_cli_lck_type lock;
72 	} db;
73 };
74 
75 struct netlogon_creds_cli_locked_state {
76 	struct netlogon_creds_cli_context *context;
77 	bool is_glocked;
78 	struct netlogon_creds_CredentialState *creds;
79 };
80 
netlogon_creds_cli_locked_state_destructor(struct netlogon_creds_cli_locked_state * state)81 static int netlogon_creds_cli_locked_state_destructor(
82 		struct netlogon_creds_cli_locked_state *state)
83 {
84 	struct netlogon_creds_cli_context *context = state->context;
85 
86 	if (context == NULL) {
87 		return 0;
88 	}
89 
90 	if (context->db.locked_state == state) {
91 		context->db.locked_state = NULL;
92 	}
93 
94 	if (state->is_glocked) {
95 		g_lock_unlock(context->db.g_ctx,
96 			      string_term_tdb_data(context->db.key_name));
97 	}
98 
99 	return 0;
100 }
101 
netlogon_creds_cli_context_common(const char * client_computer,const char * client_account,enum netr_SchannelType type,enum dcerpc_AuthLevel auth_level,uint32_t proposed_flags,uint32_t required_flags,const char * server_computer,const char * server_netbios_domain,const char * server_dns_domain,TALLOC_CTX * mem_ctx,struct netlogon_creds_cli_context ** _context)102 static NTSTATUS netlogon_creds_cli_context_common(
103 				const char *client_computer,
104 				const char *client_account,
105 				enum netr_SchannelType type,
106 				enum dcerpc_AuthLevel auth_level,
107 				uint32_t proposed_flags,
108 				uint32_t required_flags,
109 				const char *server_computer,
110 				const char *server_netbios_domain,
111 				const char *server_dns_domain,
112 				TALLOC_CTX *mem_ctx,
113 				struct netlogon_creds_cli_context **_context)
114 {
115 	struct netlogon_creds_cli_context *context = NULL;
116 	char *_key_name = NULL;
117 	size_t server_netbios_name_len;
118 	char *p = NULL;
119 
120 	*_context = NULL;
121 
122 	context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
123 	if (context == NULL) {
124 		return NT_STATUS_NO_MEMORY;
125 	}
126 
127 	context->client.computer = talloc_strdup(context, client_computer);
128 	if (context->client.computer == NULL) {
129 		TALLOC_FREE(context);
130 		return NT_STATUS_NO_MEMORY;
131 	}
132 
133 	context->client.account = talloc_strdup(context, client_account);
134 	if (context->client.account == NULL) {
135 		TALLOC_FREE(context);
136 		return NT_STATUS_NO_MEMORY;
137 	}
138 
139 	context->client.proposed_flags = proposed_flags;
140 	context->client.required_flags = required_flags;
141 	context->client.type = type;
142 	context->client.auth_level = auth_level;
143 
144 	context->server.computer = talloc_strdup(context, server_computer);
145 	if (context->server.computer == NULL) {
146 		TALLOC_FREE(context);
147 		return NT_STATUS_NO_MEMORY;
148 	}
149 
150 	context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
151 	if (context->server.netbios_domain == NULL) {
152 		TALLOC_FREE(context);
153 		return NT_STATUS_NO_MEMORY;
154 	}
155 
156 	context->server.dns_domain = talloc_strdup(context, server_dns_domain);
157 	if (context->server.dns_domain == NULL) {
158 		TALLOC_FREE(context);
159 		return NT_STATUS_NO_MEMORY;
160 	}
161 
162 	/*
163 	 * TODO:
164 	 * Force the callers to provide a unique
165 	 * value for server_computer and use this directly.
166 	 *
167 	 * For now we have to deal with
168 	 * "HOSTNAME" vs. "hostname.example.com".
169 	 */
170 
171 	p = strchr(server_computer, '.');
172 	if (p != NULL) {
173 		server_netbios_name_len = p-server_computer;
174 	} else {
175 		server_netbios_name_len = strlen(server_computer);
176 	}
177 
178 	_key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
179 				    client_computer,
180 				    client_account,
181 				    (int)server_netbios_name_len,
182 				    server_computer,
183 				    server_netbios_domain);
184 	if (_key_name == NULL) {
185 		TALLOC_FREE(context);
186 		return NT_STATUS_NO_MEMORY;
187 	}
188 
189 	context->db.key_name = talloc_strdup_upper(context, _key_name);
190 	TALLOC_FREE(_key_name);
191 	if (context->db.key_name == NULL) {
192 		TALLOC_FREE(context);
193 		return NT_STATUS_NO_MEMORY;
194 	}
195 
196 	context->db.key_data = string_term_tdb_data(context->db.key_name);
197 
198 	*_context = context;
199 	return NT_STATUS_OK;
200 }
201 
202 static struct db_context *netlogon_creds_cli_global_db;
203 
netlogon_creds_cli_set_global_db(struct db_context ** db)204 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
205 {
206 	if (netlogon_creds_cli_global_db != NULL) {
207 		return NT_STATUS_INVALID_PARAMETER_MIX;
208 	}
209 
210 	netlogon_creds_cli_global_db = talloc_move(NULL, db);
211 	return NT_STATUS_OK;
212 }
213 
netlogon_creds_cli_open_global_db(struct loadparm_context * lp_ctx)214 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
215 {
216 	char *fname;
217 	struct db_context *global_db;
218 	int hash_size, tdb_flags;
219 
220 	if (netlogon_creds_cli_global_db != NULL) {
221 		return NT_STATUS_OK;
222 	}
223 
224 	fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
225 	if (fname == NULL) {
226 		return NT_STATUS_NO_MEMORY;
227 	}
228 
229 	hash_size = lpcfg_tdb_hash_size(lp_ctx, fname);
230 	tdb_flags = lpcfg_tdb_flags(
231 		lp_ctx,
232 		TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH);
233 
234 	global_db = dbwrap_local_open(
235 		NULL,
236 		fname,
237 		hash_size,
238 		tdb_flags,
239 		O_RDWR|O_CREAT,
240 		0600,
241 		DBWRAP_LOCK_ORDER_2,
242 		DBWRAP_FLAG_NONE);
243 	if (global_db == NULL) {
244 		DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
245 			 fname, strerror(errno)));
246 		talloc_free(fname);
247 		return NT_STATUS_NO_MEMORY;
248 	}
249 	TALLOC_FREE(fname);
250 
251 	netlogon_creds_cli_global_db = global_db;
252 	return NT_STATUS_OK;
253 }
254 
netlogon_creds_cli_close_global_db(void)255 void netlogon_creds_cli_close_global_db(void)
256 {
257 	TALLOC_FREE(netlogon_creds_cli_global_db);
258 }
259 
netlogon_creds_cli_context_global(struct loadparm_context * lp_ctx,struct messaging_context * msg_ctx,const char * client_account,enum netr_SchannelType type,const char * server_computer,const char * server_netbios_domain,const char * server_dns_domain,TALLOC_CTX * mem_ctx,struct netlogon_creds_cli_context ** _context)260 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
261 				struct messaging_context *msg_ctx,
262 				const char *client_account,
263 				enum netr_SchannelType type,
264 				const char *server_computer,
265 				const char *server_netbios_domain,
266 				const char *server_dns_domain,
267 				TALLOC_CTX *mem_ctx,
268 				struct netlogon_creds_cli_context **_context)
269 {
270 	TALLOC_CTX *frame = talloc_stackframe();
271 	NTSTATUS status;
272 	struct netlogon_creds_cli_context *context = NULL;
273 	const char *client_computer;
274 	uint32_t proposed_flags;
275 	uint32_t required_flags = 0;
276 	bool reject_md5_servers = false;
277 	bool require_strong_key = false;
278 	int require_sign_or_seal = true;
279 	bool seal_secure_channel = true;
280 	enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
281 	bool neutralize_nt4_emulation = false;
282 
283 	*_context = NULL;
284 
285 	if (msg_ctx == NULL) {
286 		TALLOC_FREE(frame);
287 		return NT_STATUS_INVALID_PARAMETER_MIX;
288 	}
289 
290 	client_computer = lpcfg_netbios_name(lp_ctx);
291 	if (strlen(client_computer) > 15) {
292 		TALLOC_FREE(frame);
293 		return NT_STATUS_INVALID_PARAMETER_MIX;
294 	}
295 
296 	/*
297 	 * allow overwrite per domain
298 	 * reject md5 servers:<netbios_domain>
299 	 */
300 	reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
301 	reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
302 					     "reject md5 servers",
303 					     server_netbios_domain,
304 					     reject_md5_servers);
305 
306 	/*
307 	 * allow overwrite per domain
308 	 * require strong key:<netbios_domain>
309 	 */
310 	require_strong_key = lpcfg_require_strong_key(lp_ctx);
311 	require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
312 					     "require strong key",
313 					     server_netbios_domain,
314 					     require_strong_key);
315 
316 	/*
317 	 * allow overwrite per domain
318 	 * client schannel:<netbios_domain>
319 	 */
320 	require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
321 	require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
322 					      "client schannel",
323 					      server_netbios_domain,
324 					      require_sign_or_seal);
325 
326 	/*
327 	 * allow overwrite per domain
328 	 * winbind sealed pipes:<netbios_domain>
329 	 */
330 	seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
331 	seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
332 					      "winbind sealed pipes",
333 					      server_netbios_domain,
334 					      seal_secure_channel);
335 
336 	/*
337 	 * allow overwrite per domain
338 	 * neutralize nt4 emulation:<netbios_domain>
339 	 */
340 	neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
341 	neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
342 						   "neutralize nt4 emulation",
343 						   server_netbios_domain,
344 						   neutralize_nt4_emulation);
345 
346 	proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
347 	proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
348 
349 	switch (type) {
350 	case SEC_CHAN_WKSTA:
351 		if (lpcfg_security(lp_ctx) == SEC_ADS) {
352 			/*
353 			 * AD domains should be secure
354 			 */
355 			required_flags |= NETLOGON_NEG_PASSWORD_SET2;
356 			require_sign_or_seal = true;
357 			require_strong_key = true;
358 		}
359 		break;
360 
361 	case SEC_CHAN_DOMAIN:
362 		break;
363 
364 	case SEC_CHAN_DNS_DOMAIN:
365 		/*
366 		 * AD domains should be secure
367 		 */
368 		required_flags |= NETLOGON_NEG_PASSWORD_SET2;
369 		require_sign_or_seal = true;
370 		require_strong_key = true;
371 		neutralize_nt4_emulation = true;
372 		break;
373 
374 	case SEC_CHAN_BDC:
375 		required_flags |= NETLOGON_NEG_PASSWORD_SET2;
376 		require_sign_or_seal = true;
377 		require_strong_key = true;
378 		break;
379 
380 	case SEC_CHAN_RODC:
381 		required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
382 		required_flags |= NETLOGON_NEG_PASSWORD_SET2;
383 		require_sign_or_seal = true;
384 		require_strong_key = true;
385 		neutralize_nt4_emulation = true;
386 		break;
387 
388 	default:
389 		TALLOC_FREE(frame);
390 		return NT_STATUS_INVALID_PARAMETER;
391 	}
392 
393 	if (neutralize_nt4_emulation) {
394 		proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
395 	}
396 
397 	if (require_sign_or_seal) {
398 		required_flags |= NETLOGON_NEG_ARCFOUR;
399 		required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
400 	} else {
401 		proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
402 	}
403 
404 	if (reject_md5_servers) {
405 		required_flags |= NETLOGON_NEG_ARCFOUR;
406 		required_flags |= NETLOGON_NEG_PASSWORD_SET2;
407 		required_flags |= NETLOGON_NEG_SUPPORTS_AES;
408 		required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
409 	}
410 
411 	if (require_strong_key) {
412 		required_flags |= NETLOGON_NEG_ARCFOUR;
413 		required_flags |= NETLOGON_NEG_STRONG_KEYS;
414 		required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
415 	}
416 
417 	proposed_flags |= required_flags;
418 
419 	if (seal_secure_channel) {
420 		auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
421 	} else {
422 		auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
423 	}
424 
425 	status = netlogon_creds_cli_context_common(client_computer,
426 						   client_account,
427 						   type,
428 						   auth_level,
429 						   proposed_flags,
430 						   required_flags,
431 						   server_computer,
432 						   server_netbios_domain,
433 						   "",
434 						   mem_ctx,
435 						   &context);
436 	if (!NT_STATUS_IS_OK(status)) {
437 		TALLOC_FREE(frame);
438 		return status;
439 	}
440 
441 	context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
442 	if (context->db.g_ctx == NULL) {
443 		TALLOC_FREE(context);
444 		TALLOC_FREE(frame);
445 		return NT_STATUS_NO_MEMORY;
446 	}
447 
448 	status = netlogon_creds_cli_open_global_db(lp_ctx);
449 	if (!NT_STATUS_IS_OK(status)) {
450 		TALLOC_FREE(context);
451 		TALLOC_FREE(frame);
452 		return NT_STATUS_NO_MEMORY;
453 	}
454 
455 	context->db.ctx = netlogon_creds_cli_global_db;
456 	*_context = context;
457 	TALLOC_FREE(frame);
458 	return NT_STATUS_OK;
459 }
460 
netlogon_creds_bind_cli_credentials(struct netlogon_creds_cli_context * context,TALLOC_CTX * mem_ctx,struct cli_credentials ** pcli_creds)461 NTSTATUS netlogon_creds_bind_cli_credentials(
462 	struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
463 	struct cli_credentials **pcli_creds)
464 {
465 	struct cli_credentials *cli_creds;
466 	struct netlogon_creds_CredentialState *ncreds;
467 	NTSTATUS status;
468 
469 	cli_creds = cli_credentials_init(mem_ctx);
470 	if (cli_creds == NULL) {
471 		return NT_STATUS_NO_MEMORY;
472 	}
473 	cli_credentials_set_secure_channel_type(cli_creds,
474 						context->client.type);
475 	cli_credentials_set_username(cli_creds, context->client.account,
476 				     CRED_SPECIFIED);
477 	cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
478 				   CRED_SPECIFIED);
479 	cli_credentials_set_realm(cli_creds, context->server.dns_domain,
480 				  CRED_SPECIFIED);
481 
482 	status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
483 	if (!NT_STATUS_IS_OK(status)) {
484 		TALLOC_FREE(cli_creds);
485 		return status;
486 	}
487 	cli_credentials_set_netlogon_creds(cli_creds, ncreds);
488 
489 	*pcli_creds = cli_creds;
490 	return NT_STATUS_OK;
491 }
492 
netlogon_creds_cli_debug_string(const struct netlogon_creds_cli_context * context,TALLOC_CTX * mem_ctx)493 char *netlogon_creds_cli_debug_string(
494 		const struct netlogon_creds_cli_context *context,
495 		TALLOC_CTX *mem_ctx)
496 {
497 	return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
498 			       context->db.key_name);
499 }
500 
netlogon_creds_cli_auth_level(struct netlogon_creds_cli_context * context)501 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
502 		struct netlogon_creds_cli_context *context)
503 {
504 	return context->client.auth_level;
505 }
506 
507 struct netlogon_creds_cli_fetch_state {
508 	TALLOC_CTX *mem_ctx;
509 	struct netlogon_creds_CredentialState *creds;
510 	uint32_t required_flags;
511 	NTSTATUS status;
512 };
513 
netlogon_creds_cli_fetch_parser(TDB_DATA key,TDB_DATA data,void * private_data)514 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
515 					    void *private_data)
516 {
517 	struct netlogon_creds_cli_fetch_state *state =
518 		(struct netlogon_creds_cli_fetch_state *)private_data;
519 	enum ndr_err_code ndr_err;
520 	DATA_BLOB blob;
521 	uint32_t tmp_flags;
522 
523 	state->creds = talloc_zero(state->mem_ctx,
524 				   struct netlogon_creds_CredentialState);
525 	if (state->creds == NULL) {
526 		state->status = NT_STATUS_NO_MEMORY;
527 		return;
528 	}
529 
530 	blob.data = data.dptr;
531 	blob.length = data.dsize;
532 
533 	ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
534 		(ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
535 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
536 		TALLOC_FREE(state->creds);
537 		state->status = ndr_map_error2ntstatus(ndr_err);
538 		return;
539 	}
540 
541 	if (DEBUGLEVEL >= 10) {
542 		NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
543 	}
544 
545 	tmp_flags = state->creds->negotiate_flags;
546 	tmp_flags &= state->required_flags;
547 	if (tmp_flags != state->required_flags) {
548 		TALLOC_FREE(state->creds);
549 		state->status = NT_STATUS_DOWNGRADE_DETECTED;
550 		return;
551 	}
552 
553 	state->status = NT_STATUS_OK;
554 }
555 
556 static NTSTATUS netlogon_creds_cli_get_internal(
557 	struct netlogon_creds_cli_context *context,
558 	TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
559 
netlogon_creds_cli_get(struct netlogon_creds_cli_context * context,TALLOC_CTX * mem_ctx,struct netlogon_creds_CredentialState ** _creds)560 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
561 				TALLOC_CTX *mem_ctx,
562 				struct netlogon_creds_CredentialState **_creds)
563 {
564 	NTSTATUS status;
565 	struct netlogon_creds_CredentialState *creds;
566 
567 	*_creds = NULL;
568 
569 	status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
570 	if (!NT_STATUS_IS_OK(status)) {
571 		return status;
572 	}
573 
574 	/*
575 	 * mark it as invalid for step operations.
576 	 */
577 	creds->sequence = 0;
578 	creds->seed = (struct netr_Credential) {{0}};
579 	creds->client = (struct netr_Credential) {{0}};
580 	creds->server = (struct netr_Credential) {{0}};
581 
582 	*_creds = creds;
583 	return NT_STATUS_OK;
584 }
585 
netlogon_creds_cli_validate(struct netlogon_creds_cli_context * context,const struct netlogon_creds_CredentialState * creds1)586 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
587 			const struct netlogon_creds_CredentialState *creds1)
588 {
589 	TALLOC_CTX *frame = talloc_stackframe();
590 	struct netlogon_creds_CredentialState *creds2;
591 	DATA_BLOB blob1;
592 	DATA_BLOB blob2;
593 	NTSTATUS status;
594 	enum ndr_err_code ndr_err;
595 	int cmp;
596 
597 	status = netlogon_creds_cli_get(context, frame, &creds2);
598 	if (!NT_STATUS_IS_OK(status)) {
599 		TALLOC_FREE(frame);
600 		return false;
601 	}
602 
603 	ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
604 		(ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
605 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
606 		TALLOC_FREE(frame);
607 		return false;
608 	}
609 
610 	ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
611 		(ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
612 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
613 		TALLOC_FREE(frame);
614 		return false;
615 	}
616 
617 	cmp = data_blob_cmp(&blob1, &blob2);
618 
619 	TALLOC_FREE(frame);
620 
621 	return (cmp == 0);
622 }
623 
netlogon_creds_cli_store_internal(struct netlogon_creds_cli_context * context,struct netlogon_creds_CredentialState * creds)624 static NTSTATUS netlogon_creds_cli_store_internal(
625 	struct netlogon_creds_cli_context *context,
626 	struct netlogon_creds_CredentialState *creds)
627 {
628 	NTSTATUS status;
629 	enum ndr_err_code ndr_err;
630 	DATA_BLOB blob;
631 	TDB_DATA data;
632 
633 	if (DEBUGLEVEL >= 10) {
634 		NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
635 	}
636 
637 	ndr_err = ndr_push_struct_blob(&blob, creds, creds,
638 		(ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
639 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
640 		status = ndr_map_error2ntstatus(ndr_err);
641 		return status;
642 	}
643 
644 	data.dptr = blob.data;
645 	data.dsize = blob.length;
646 
647 	status = dbwrap_store(context->db.ctx,
648 			      context->db.key_data,
649 			      data, TDB_REPLACE);
650 	TALLOC_FREE(data.dptr);
651 	if (!NT_STATUS_IS_OK(status)) {
652 		return status;
653 	}
654 
655 	return NT_STATUS_OK;
656 }
657 
netlogon_creds_cli_store(struct netlogon_creds_cli_context * context,struct netlogon_creds_CredentialState * creds)658 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
659 				  struct netlogon_creds_CredentialState *creds)
660 {
661 	NTSTATUS status;
662 
663 	if (context->db.locked_state == NULL) {
664 		/*
665 		 * this was not the result of netlogon_creds_cli_lock*()
666 		 */
667 		return NT_STATUS_INVALID_PAGE_PROTECTION;
668 	}
669 
670 	if (context->db.locked_state->creds != creds) {
671 		/*
672 		 * this was not the result of netlogon_creds_cli_lock*()
673 		 */
674 		return NT_STATUS_INVALID_PAGE_PROTECTION;
675 	}
676 
677 	status = netlogon_creds_cli_store_internal(context, creds);
678 	return status;
679 }
680 
netlogon_creds_cli_delete_internal(struct netlogon_creds_cli_context * context)681 static NTSTATUS netlogon_creds_cli_delete_internal(
682 	struct netlogon_creds_cli_context *context)
683 {
684 	NTSTATUS status;
685 	status = dbwrap_delete(context->db.ctx, context->db.key_data);
686 	return status;
687 }
688 
netlogon_creds_cli_delete_lck(struct netlogon_creds_cli_context * context)689 NTSTATUS netlogon_creds_cli_delete_lck(
690 	struct netlogon_creds_cli_context *context)
691 {
692 	NTSTATUS status;
693 
694 	if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
695 		return NT_STATUS_NOT_LOCKED;
696 	}
697 
698 	status = netlogon_creds_cli_delete_internal(context);
699 	return status;
700 }
701 
netlogon_creds_cli_delete(struct netlogon_creds_cli_context * context,struct netlogon_creds_CredentialState * creds)702 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
703 				   struct netlogon_creds_CredentialState *creds)
704 {
705 	NTSTATUS status;
706 
707 	if (context->db.locked_state == NULL) {
708 		/*
709 		 * this was not the result of netlogon_creds_cli_lock*()
710 		 */
711 		return NT_STATUS_INVALID_PAGE_PROTECTION;
712 	}
713 
714 	if (context->db.locked_state->creds != creds) {
715 		/*
716 		 * this was not the result of netlogon_creds_cli_lock*()
717 		 */
718 		return NT_STATUS_INVALID_PAGE_PROTECTION;
719 	}
720 
721 	status = netlogon_creds_cli_delete_internal(context);
722 	return status;
723 }
724 
725 struct netlogon_creds_cli_lock_state {
726 	struct netlogon_creds_cli_locked_state *locked_state;
727 	struct netlogon_creds_CredentialState *creds;
728 };
729 
730 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
731 
netlogon_creds_cli_lock_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct netlogon_creds_cli_context * context)732 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
733 				struct tevent_context *ev,
734 				struct netlogon_creds_cli_context *context)
735 {
736 	struct tevent_req *req;
737 	struct netlogon_creds_cli_lock_state *state;
738 	struct netlogon_creds_cli_locked_state *locked_state;
739 	struct tevent_req *subreq;
740 
741 	req = tevent_req_create(mem_ctx, &state,
742 				struct netlogon_creds_cli_lock_state);
743 	if (req == NULL) {
744 		return NULL;
745 	}
746 
747 	if (context->db.locked_state != NULL) {
748 		tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
749 		return tevent_req_post(req, ev);
750 	}
751 
752 	locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
753 	if (tevent_req_nomem(locked_state, req)) {
754 		return tevent_req_post(req, ev);
755 	}
756 	talloc_set_destructor(locked_state,
757 			      netlogon_creds_cli_locked_state_destructor);
758 	locked_state->context = context;
759 
760 	context->db.locked_state = locked_state;
761 	state->locked_state = locked_state;
762 
763 	if (context->db.g_ctx == NULL) {
764 		NTSTATUS status;
765 
766 		status = netlogon_creds_cli_get_internal(
767 			context, state, &state->creds);
768 		if (tevent_req_nterror(req, status)) {
769 			return tevent_req_post(req, ev);
770 		}
771 
772 		return req;
773 	}
774 
775 	subreq = g_lock_lock_send(state, ev,
776 				  context->db.g_ctx,
777 				  string_term_tdb_data(context->db.key_name),
778 				  G_LOCK_WRITE);
779 	if (tevent_req_nomem(subreq, req)) {
780 		return tevent_req_post(req, ev);
781 	}
782 	tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
783 
784 	return req;
785 }
786 
netlogon_creds_cli_lock_done(struct tevent_req * subreq)787 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
788 {
789 	struct tevent_req *req =
790 		tevent_req_callback_data(subreq,
791 		struct tevent_req);
792 	struct netlogon_creds_cli_lock_state *state =
793 		tevent_req_data(req,
794 		struct netlogon_creds_cli_lock_state);
795 	NTSTATUS status;
796 
797 	status = g_lock_lock_recv(subreq);
798 	TALLOC_FREE(subreq);
799 	if (tevent_req_nterror(req, status)) {
800 		return;
801 	}
802 	state->locked_state->is_glocked = true;
803 
804 	status = netlogon_creds_cli_get_internal(state->locked_state->context,
805 					       state, &state->creds);
806 	if (tevent_req_nterror(req, status)) {
807 		return;
808 	}
809 	tevent_req_done(req);
810 }
811 
netlogon_creds_cli_get_internal(struct netlogon_creds_cli_context * context,TALLOC_CTX * mem_ctx,struct netlogon_creds_CredentialState ** pcreds)812 static NTSTATUS netlogon_creds_cli_get_internal(
813 	struct netlogon_creds_cli_context *context,
814 	TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
815 {
816 	struct netlogon_creds_cli_fetch_state fstate = {
817 		.status = NT_STATUS_INTERNAL_ERROR,
818 		.required_flags = context->client.required_flags,
819 	};
820 	NTSTATUS status;
821 
822 	fstate.mem_ctx = mem_ctx;
823 	status = dbwrap_parse_record(context->db.ctx,
824 				     context->db.key_data,
825 				     netlogon_creds_cli_fetch_parser,
826 				     &fstate);
827 	if (!NT_STATUS_IS_OK(status)) {
828 		return status;
829 	}
830 	if (!NT_STATUS_IS_OK(fstate.status)) {
831 		return fstate.status;
832 	}
833 
834 	if (context->server.cached_flags == fstate.creds->negotiate_flags) {
835 		*pcreds = fstate.creds;
836 		return NT_STATUS_OK;
837 	}
838 
839 	/*
840 	 * It is really important to try SamLogonEx here,
841 	 * because multiple processes can talk to the same
842 	 * domain controller, without using the credential
843 	 * chain.
844 	 *
845 	 * With a normal SamLogon call, we must keep the
846 	 * credentials chain updated and intact between all
847 	 * users of the machine account (which would imply
848 	 * cross-node communication for every NTLM logon).
849 	 *
850 	 * The credentials chain is not per NETLOGON pipe
851 	 * connection, but globally on the server/client pair
852 	 * by computer name.
853 	 *
854 	 * It's also important to use NetlogonValidationSamInfo4 (6),
855 	 * because it relies on the rpc transport encryption
856 	 * and avoids using the global netlogon schannel
857 	 * session key to en/decrypt secret information
858 	 * like the user_session_key for network logons.
859 	 *
860 	 * [MS-APDS] 3.1.5.2 NTLM Network Logon
861 	 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
862 	 * NETLOGON_NEG_AUTHENTICATED_RPC set together
863 	 * are the indication that the server supports
864 	 * NetlogonValidationSamInfo4 (6). And it must only
865 	 * be used if "SealSecureChannel" is used.
866 	 *
867 	 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
868 	 * check is done in netlogon_creds_cli_LogonSamLogon*().
869 	 */
870 
871 	context->server.cached_flags = fstate.creds->negotiate_flags;
872 	context->server.try_validation6 = true;
873 	context->server.try_logon_ex = true;
874 	context->server.try_logon_with = true;
875 
876 	if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
877 		context->server.try_validation6 = false;
878 		context->server.try_logon_ex = false;
879 	}
880 	if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
881 		context->server.try_validation6 = false;
882 	}
883 
884 	*pcreds = fstate.creds;
885 	return NT_STATUS_OK;
886 }
887 
netlogon_creds_cli_lock_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,struct netlogon_creds_CredentialState ** creds)888 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
889 			TALLOC_CTX *mem_ctx,
890 			struct netlogon_creds_CredentialState **creds)
891 {
892 	struct netlogon_creds_cli_lock_state *state =
893 		tevent_req_data(req,
894 		struct netlogon_creds_cli_lock_state);
895 	NTSTATUS status;
896 
897 	if (tevent_req_is_nterror(req, &status)) {
898 		tevent_req_received(req);
899 		return status;
900 	}
901 
902 	talloc_steal(state->creds, state->locked_state);
903 	state->locked_state->creds = state->creds;
904 	*creds = talloc_move(mem_ctx, &state->creds);
905 	tevent_req_received(req);
906 	return NT_STATUS_OK;
907 }
908 
netlogon_creds_cli_lock(struct netlogon_creds_cli_context * context,TALLOC_CTX * mem_ctx,struct netlogon_creds_CredentialState ** creds)909 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
910 			TALLOC_CTX *mem_ctx,
911 			struct netlogon_creds_CredentialState **creds)
912 {
913 	TALLOC_CTX *frame = talloc_stackframe();
914 	struct tevent_context *ev;
915 	struct tevent_req *req;
916 	NTSTATUS status = NT_STATUS_NO_MEMORY;
917 
918 	ev = samba_tevent_context_init(frame);
919 	if (ev == NULL) {
920 		goto fail;
921 	}
922 	req = netlogon_creds_cli_lock_send(frame, ev, context);
923 	if (req == NULL) {
924 		goto fail;
925 	}
926 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
927 		goto fail;
928 	}
929 	status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
930  fail:
931 	TALLOC_FREE(frame);
932 	return status;
933 }
934 
935 struct netlogon_creds_cli_lck {
936 	struct netlogon_creds_cli_context *context;
937 };
938 
939 struct netlogon_creds_cli_lck_state {
940 	struct netlogon_creds_cli_lck *lck;
941 	enum netlogon_creds_cli_lck_type type;
942 };
943 
944 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
945 static int netlogon_creds_cli_lck_destructor(
946 	struct netlogon_creds_cli_lck *lck);
947 
netlogon_creds_cli_lck_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct netlogon_creds_cli_context * context,enum netlogon_creds_cli_lck_type type)948 struct tevent_req *netlogon_creds_cli_lck_send(
949 	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
950 	struct netlogon_creds_cli_context *context,
951 	enum netlogon_creds_cli_lck_type type)
952 {
953 	struct tevent_req *req, *subreq;
954 	struct netlogon_creds_cli_lck_state *state;
955 	enum g_lock_type gtype;
956 
957 	req = tevent_req_create(mem_ctx, &state,
958 				struct netlogon_creds_cli_lck_state);
959 	if (req == NULL) {
960 		return NULL;
961 	}
962 
963 	if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
964 		DBG_DEBUG("context already locked\n");
965 		tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
966 		return tevent_req_post(req, ev);
967 	}
968 
969 	switch (type) {
970 	    case NETLOGON_CREDS_CLI_LCK_SHARED:
971 		    gtype = G_LOCK_READ;
972 		    break;
973 	    case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
974 		    gtype = G_LOCK_WRITE;
975 		    break;
976 	    default:
977 		    tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
978 		    return tevent_req_post(req, ev);
979 	}
980 
981 	state->lck = talloc(state, struct netlogon_creds_cli_lck);
982 	if (tevent_req_nomem(state->lck, req)) {
983 		return tevent_req_post(req, ev);
984 	}
985 	state->lck->context = context;
986 	state->type = type;
987 
988 	subreq = g_lock_lock_send(state, ev,
989 				  context->db.g_ctx,
990 				  string_term_tdb_data(context->db.key_name),
991 				  gtype);
992 	if (tevent_req_nomem(subreq, req)) {
993 		return tevent_req_post(req, ev);
994 	}
995 	tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
996 
997 	return req;
998 }
999 
netlogon_creds_cli_lck_locked(struct tevent_req * subreq)1000 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
1001 {
1002 	struct tevent_req *req = tevent_req_callback_data(
1003 		subreq, struct tevent_req);
1004 	struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1005 		req, struct netlogon_creds_cli_lck_state);
1006 	NTSTATUS status;
1007 
1008 	status = g_lock_lock_recv(subreq);
1009 	TALLOC_FREE(subreq);
1010 	if (tevent_req_nterror(req, status)) {
1011 		return;
1012 	}
1013 
1014 	state->lck->context->db.lock = state->type;
1015 	talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
1016 
1017 	tevent_req_done(req);
1018 }
1019 
netlogon_creds_cli_lck_destructor(struct netlogon_creds_cli_lck * lck)1020 static int netlogon_creds_cli_lck_destructor(
1021 	struct netlogon_creds_cli_lck *lck)
1022 {
1023 	struct netlogon_creds_cli_context *ctx = lck->context;
1024 	NTSTATUS status;
1025 
1026 	status = g_lock_unlock(ctx->db.g_ctx,
1027 			       string_term_tdb_data(ctx->db.key_name));
1028 	if (!NT_STATUS_IS_OK(status)) {
1029 		DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
1030 		smb_panic("g_lock_unlock failed");
1031 	}
1032 	ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
1033 	return 0;
1034 }
1035 
netlogon_creds_cli_lck_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,struct netlogon_creds_cli_lck ** lck)1036 NTSTATUS netlogon_creds_cli_lck_recv(
1037 	struct tevent_req *req, TALLOC_CTX *mem_ctx,
1038 	struct netlogon_creds_cli_lck **lck)
1039 {
1040 	struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1041 		req, struct netlogon_creds_cli_lck_state);
1042 	NTSTATUS status;
1043 
1044 	if (tevent_req_is_nterror(req, &status)) {
1045 		return status;
1046 	}
1047 	*lck = talloc_move(mem_ctx, &state->lck);
1048 	return NT_STATUS_OK;
1049 }
1050 
netlogon_creds_cli_lck(struct netlogon_creds_cli_context * context,enum netlogon_creds_cli_lck_type type,TALLOC_CTX * mem_ctx,struct netlogon_creds_cli_lck ** lck)1051 NTSTATUS netlogon_creds_cli_lck(
1052 	struct netlogon_creds_cli_context *context,
1053 	enum netlogon_creds_cli_lck_type type,
1054 	TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
1055 {
1056 	TALLOC_CTX *frame = talloc_stackframe();
1057 	struct tevent_context *ev;
1058 	struct tevent_req *req;
1059 	NTSTATUS status = NT_STATUS_NO_MEMORY;
1060 
1061 	ev = samba_tevent_context_init(frame);
1062 	if (ev == NULL) {
1063 		goto fail;
1064 	}
1065 	req = netlogon_creds_cli_lck_send(frame, ev, context, type);
1066 	if (req == NULL) {
1067 		goto fail;
1068 	}
1069 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1070 		goto fail;
1071 	}
1072 	status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
1073  fail:
1074 	TALLOC_FREE(frame);
1075 	return status;
1076 }
1077 
1078 struct netlogon_creds_cli_auth_state {
1079 	struct tevent_context *ev;
1080 	struct netlogon_creds_cli_context *context;
1081 	struct dcerpc_binding_handle *binding_handle;
1082 	uint8_t num_nt_hashes;
1083 	uint8_t idx_nt_hashes;
1084 	const struct samr_Password * const *nt_hashes;
1085 	const struct samr_Password *used_nt_hash;
1086 	char *srv_name_slash;
1087 	uint32_t current_flags;
1088 	struct netr_Credential client_challenge;
1089 	struct netr_Credential server_challenge;
1090 	struct netlogon_creds_CredentialState *creds;
1091 	struct netr_Credential client_credential;
1092 	struct netr_Credential server_credential;
1093 	uint32_t rid;
1094 	bool try_auth3;
1095 	bool try_auth2;
1096 	bool require_auth2;
1097 };
1098 
1099 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
1100 
netlogon_creds_cli_auth_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b,uint8_t num_nt_hashes,const struct samr_Password * const * nt_hashes)1101 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
1102 				struct tevent_context *ev,
1103 				struct netlogon_creds_cli_context *context,
1104 				struct dcerpc_binding_handle *b,
1105 				uint8_t num_nt_hashes,
1106 				const struct samr_Password * const *nt_hashes)
1107 {
1108 	struct tevent_req *req;
1109 	struct netlogon_creds_cli_auth_state *state;
1110 	NTSTATUS status;
1111 
1112 	req = tevent_req_create(mem_ctx, &state,
1113 				struct netlogon_creds_cli_auth_state);
1114 	if (req == NULL) {
1115 		return NULL;
1116 	}
1117 
1118 	state->ev = ev;
1119 	state->context = context;
1120 	state->binding_handle = b;
1121 	if (num_nt_hashes < 1) {
1122 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1123 		return tevent_req_post(req, ev);
1124 	}
1125 	if (num_nt_hashes > 4) {
1126 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1127 		return tevent_req_post(req, ev);
1128 	}
1129 
1130 	state->num_nt_hashes = num_nt_hashes;
1131 	state->idx_nt_hashes = 0;
1132 	state->nt_hashes = nt_hashes;
1133 
1134 	if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1135 		tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1136 		return tevent_req_post(req, ev);
1137 	}
1138 
1139 	state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1140 						context->server.computer);
1141 	if (tevent_req_nomem(state->srv_name_slash, req)) {
1142 		return tevent_req_post(req, ev);
1143 	}
1144 
1145 	state->try_auth3 = true;
1146 	state->try_auth2 = true;
1147 
1148 	if (context->client.required_flags != 0) {
1149 		state->require_auth2 = true;
1150 	}
1151 
1152 	state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1153 	state->current_flags = context->client.proposed_flags;
1154 
1155 	status = dbwrap_purge(state->context->db.ctx,
1156 			      state->context->db.key_data);
1157 	if (tevent_req_nterror(req, status)) {
1158 		return tevent_req_post(req, ev);
1159 	}
1160 
1161 	netlogon_creds_cli_auth_challenge_start(req);
1162 	if (!tevent_req_is_in_progress(req)) {
1163 		return tevent_req_post(req, ev);
1164 	}
1165 
1166 	return req;
1167 }
1168 
1169 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1170 
netlogon_creds_cli_auth_challenge_start(struct tevent_req * req)1171 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1172 {
1173 	struct netlogon_creds_cli_auth_state *state =
1174 		tevent_req_data(req,
1175 		struct netlogon_creds_cli_auth_state);
1176 	struct tevent_req *subreq;
1177 
1178 	TALLOC_FREE(state->creds);
1179 
1180 	netlogon_creds_random_challenge(&state->client_challenge);
1181 
1182 	subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1183 						state->binding_handle,
1184 						state->srv_name_slash,
1185 						state->context->client.computer,
1186 						&state->client_challenge,
1187 						&state->server_challenge);
1188 	if (tevent_req_nomem(subreq, req)) {
1189 		return;
1190 	}
1191 	tevent_req_set_callback(subreq,
1192 				netlogon_creds_cli_auth_challenge_done,
1193 				req);
1194 }
1195 
1196 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1197 
netlogon_creds_cli_auth_challenge_done(struct tevent_req * subreq)1198 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1199 {
1200 	struct tevent_req *req =
1201 		tevent_req_callback_data(subreq,
1202 		struct tevent_req);
1203 	struct netlogon_creds_cli_auth_state *state =
1204 		tevent_req_data(req,
1205 		struct netlogon_creds_cli_auth_state);
1206 	NTSTATUS status;
1207 	NTSTATUS result;
1208 
1209 	status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1210 	TALLOC_FREE(subreq);
1211 	if (tevent_req_nterror(req, status)) {
1212 		return;
1213 	}
1214 	if (tevent_req_nterror(req, result)) {
1215 		return;
1216 	}
1217 
1218 	if (!state->try_auth3 && !state->try_auth2) {
1219 		state->current_flags = 0;
1220 	}
1221 
1222 	/* Calculate the session key and client credentials */
1223 
1224 	state->creds = netlogon_creds_client_init(state,
1225 						  state->context->client.account,
1226 						  state->context->client.computer,
1227 						  state->context->client.type,
1228 						  &state->client_challenge,
1229 						  &state->server_challenge,
1230 						  state->used_nt_hash,
1231 						  &state->client_credential,
1232 						  state->current_flags);
1233 	if (tevent_req_nomem(state->creds, req)) {
1234 		return;
1235 	}
1236 
1237 	if (state->try_auth3) {
1238 		subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1239 						state->binding_handle,
1240 						state->srv_name_slash,
1241 						state->context->client.account,
1242 						state->context->client.type,
1243 						state->context->client.computer,
1244 						&state->client_credential,
1245 						&state->server_credential,
1246 						&state->creds->negotiate_flags,
1247 						&state->rid);
1248 		if (tevent_req_nomem(subreq, req)) {
1249 			return;
1250 		}
1251 	} else if (state->try_auth2) {
1252 		state->rid = 0;
1253 
1254 		subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1255 						state->binding_handle,
1256 						state->srv_name_slash,
1257 						state->context->client.account,
1258 						state->context->client.type,
1259 						state->context->client.computer,
1260 						&state->client_credential,
1261 						&state->server_credential,
1262 						&state->creds->negotiate_flags);
1263 		if (tevent_req_nomem(subreq, req)) {
1264 			return;
1265 		}
1266 	} else {
1267 		state->rid = 0;
1268 
1269 		subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1270 						state->binding_handle,
1271 						state->srv_name_slash,
1272 						state->context->client.account,
1273 						state->context->client.type,
1274 						state->context->client.computer,
1275 						&state->client_credential,
1276 						&state->server_credential);
1277 		if (tevent_req_nomem(subreq, req)) {
1278 			return;
1279 		}
1280 	}
1281 	tevent_req_set_callback(subreq,
1282 				netlogon_creds_cli_auth_srvauth_done,
1283 				req);
1284 }
1285 
netlogon_creds_cli_auth_srvauth_done(struct tevent_req * subreq)1286 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1287 {
1288 	struct tevent_req *req =
1289 		tevent_req_callback_data(subreq,
1290 		struct tevent_req);
1291 	struct netlogon_creds_cli_auth_state *state =
1292 		tevent_req_data(req,
1293 		struct netlogon_creds_cli_auth_state);
1294 	NTSTATUS status;
1295 	NTSTATUS result;
1296 	bool ok;
1297 	enum ndr_err_code ndr_err;
1298 	DATA_BLOB blob;
1299 	TDB_DATA data;
1300 	uint32_t tmp_flags;
1301 
1302 	if (state->try_auth3) {
1303 		status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1304 							      &result);
1305 		TALLOC_FREE(subreq);
1306 		if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1307 			state->try_auth3 = false;
1308 			netlogon_creds_cli_auth_challenge_start(req);
1309 			return;
1310 		}
1311 		if (tevent_req_nterror(req, status)) {
1312 			return;
1313 		}
1314 	} else if (state->try_auth2) {
1315 		status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1316 							      &result);
1317 		TALLOC_FREE(subreq);
1318 		if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1319 			state->try_auth2 = false;
1320 			if (state->require_auth2) {
1321 				status = NT_STATUS_DOWNGRADE_DETECTED;
1322 				tevent_req_nterror(req, status);
1323 				return;
1324 			}
1325 			netlogon_creds_cli_auth_challenge_start(req);
1326 			return;
1327 		}
1328 		if (tevent_req_nterror(req, status)) {
1329 			return;
1330 		}
1331 	} else {
1332 		status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1333 							     &result);
1334 		TALLOC_FREE(subreq);
1335 		if (tevent_req_nterror(req, status)) {
1336 			return;
1337 		}
1338 	}
1339 
1340 	if (!NT_STATUS_IS_OK(result) &&
1341 	    !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1342 	{
1343 		tevent_req_nterror(req, result);
1344 		return;
1345 	}
1346 
1347 	tmp_flags = state->creds->negotiate_flags;
1348 	tmp_flags &= state->context->client.required_flags;
1349 	if (tmp_flags != state->context->client.required_flags) {
1350 		if (NT_STATUS_IS_OK(result)) {
1351 			tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1352 			return;
1353 		}
1354 		tevent_req_nterror(req, result);
1355 		return;
1356 	}
1357 
1358 	if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1359 
1360 		tmp_flags = state->context->client.proposed_flags;
1361 		if ((state->current_flags == tmp_flags) &&
1362 		    (state->creds->negotiate_flags != tmp_flags))
1363 		{
1364 			/*
1365 			 * lets retry with the negotiated flags
1366 			 */
1367 			state->current_flags = state->creds->negotiate_flags;
1368 			netlogon_creds_cli_auth_challenge_start(req);
1369 			return;
1370 		}
1371 
1372 		state->idx_nt_hashes += 1;
1373 		if (state->idx_nt_hashes >= state->num_nt_hashes) {
1374 			/*
1375 			 * we already retried, giving up...
1376 			 */
1377 			tevent_req_nterror(req, result);
1378 			return;
1379 		}
1380 
1381 		/*
1382 		 * lets retry with the old nt hash.
1383 		 */
1384 		state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1385 		state->current_flags = state->context->client.proposed_flags;
1386 		netlogon_creds_cli_auth_challenge_start(req);
1387 		return;
1388 	}
1389 
1390 	ok = netlogon_creds_client_check(state->creds,
1391 					 &state->server_credential);
1392 	if (!ok) {
1393 		tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1394 		return;
1395 	}
1396 
1397 	ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1398 		(ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1399 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1400 		status = ndr_map_error2ntstatus(ndr_err);
1401 		tevent_req_nterror(req, status);
1402 		return;
1403 	}
1404 
1405 	data.dptr = blob.data;
1406 	data.dsize = blob.length;
1407 
1408 	status = dbwrap_store(state->context->db.ctx,
1409 			      state->context->db.key_data,
1410 			      data, TDB_REPLACE);
1411 	if (tevent_req_nterror(req, status)) {
1412 		return;
1413 	}
1414 
1415 	tevent_req_done(req);
1416 }
1417 
netlogon_creds_cli_auth_recv(struct tevent_req * req,uint8_t * idx_nt_hashes)1418 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1419 				      uint8_t *idx_nt_hashes)
1420 {
1421 	struct netlogon_creds_cli_auth_state *state =
1422 		tevent_req_data(req,
1423 		struct netlogon_creds_cli_auth_state);
1424 	NTSTATUS status;
1425 
1426 	*idx_nt_hashes = 0;
1427 
1428 	if (tevent_req_is_nterror(req, &status)) {
1429 		tevent_req_received(req);
1430 		return status;
1431 	}
1432 
1433 	*idx_nt_hashes = state->idx_nt_hashes;
1434 	tevent_req_received(req);
1435 	return NT_STATUS_OK;
1436 }
1437 
netlogon_creds_cli_auth(struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b,uint8_t num_nt_hashes,const struct samr_Password * const * nt_hashes,uint8_t * idx_nt_hashes)1438 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1439 				 struct dcerpc_binding_handle *b,
1440 				 uint8_t num_nt_hashes,
1441 				 const struct samr_Password * const *nt_hashes,
1442 				 uint8_t *idx_nt_hashes)
1443 {
1444 	TALLOC_CTX *frame = talloc_stackframe();
1445 	struct tevent_context *ev;
1446 	struct tevent_req *req;
1447 	NTSTATUS status = NT_STATUS_NO_MEMORY;
1448 
1449 	*idx_nt_hashes = 0;
1450 
1451 	ev = samba_tevent_context_init(frame);
1452 	if (ev == NULL) {
1453 		goto fail;
1454 	}
1455 	req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1456 					   num_nt_hashes, nt_hashes);
1457 	if (req == NULL) {
1458 		goto fail;
1459 	}
1460 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1461 		goto fail;
1462 	}
1463 	status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1464  fail:
1465 	TALLOC_FREE(frame);
1466 	return status;
1467 }
1468 
1469 struct netlogon_creds_cli_check_state {
1470 	struct tevent_context *ev;
1471 	struct netlogon_creds_cli_context *context;
1472 	struct dcerpc_binding_handle *binding_handle;
1473 
1474 	char *srv_name_slash;
1475 
1476 	union netr_Capabilities caps;
1477 
1478 	struct netlogon_creds_CredentialState *creds;
1479 	struct netr_Authenticator req_auth;
1480 	struct netr_Authenticator rep_auth;
1481 };
1482 
1483 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1484 					     NTSTATUS status);
1485 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1486 
netlogon_creds_cli_check_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b)1487 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1488 				struct tevent_context *ev,
1489 				struct netlogon_creds_cli_context *context,
1490 				struct dcerpc_binding_handle *b)
1491 {
1492 	struct tevent_req *req;
1493 	struct netlogon_creds_cli_check_state *state;
1494 	struct tevent_req *subreq;
1495 	enum dcerpc_AuthType auth_type;
1496 	enum dcerpc_AuthLevel auth_level;
1497 	NTSTATUS status;
1498 
1499 	req = tevent_req_create(mem_ctx, &state,
1500 				struct netlogon_creds_cli_check_state);
1501 	if (req == NULL) {
1502 		return NULL;
1503 	}
1504 
1505 	state->ev = ev;
1506 	state->context = context;
1507 	state->binding_handle = b;
1508 
1509 	if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1510 		tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1511 		return tevent_req_post(req, ev);
1512 	}
1513 
1514 	status = netlogon_creds_cli_get_internal(context, state,
1515 						 &state->creds);
1516 	if (tevent_req_nterror(req, status)) {
1517 		return tevent_req_post(req, ev);
1518 	}
1519 
1520 	state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1521 						context->server.computer);
1522 	if (tevent_req_nomem(state->srv_name_slash, req)) {
1523 		return tevent_req_post(req, ev);
1524 	}
1525 
1526 	dcerpc_binding_handle_auth_info(state->binding_handle,
1527 					&auth_type, &auth_level);
1528 
1529 	if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1530 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1531 		return tevent_req_post(req, ev);
1532 	}
1533 
1534 	switch (auth_level) {
1535 	case DCERPC_AUTH_LEVEL_INTEGRITY:
1536 	case DCERPC_AUTH_LEVEL_PRIVACY:
1537 		break;
1538 	default:
1539 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1540 		return tevent_req_post(req, ev);
1541 	}
1542 
1543 	/*
1544 	 * we defer all callbacks in order to cleanup
1545 	 * the database record.
1546 	 */
1547 	tevent_req_defer_callback(req, state->ev);
1548 
1549 	status = netlogon_creds_client_authenticator(state->creds,
1550 						     &state->req_auth);
1551 	if (tevent_req_nterror(req, status)) {
1552 		return tevent_req_post(req, ev);
1553 	}
1554 	ZERO_STRUCT(state->rep_auth);
1555 
1556 	subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1557 						state->binding_handle,
1558 						state->srv_name_slash,
1559 						state->context->client.computer,
1560 						&state->req_auth,
1561 						&state->rep_auth,
1562 						1,
1563 						&state->caps);
1564 	if (tevent_req_nomem(subreq, req)) {
1565 		return tevent_req_post(req, ev);
1566 	}
1567 
1568 	tevent_req_set_callback(subreq,
1569 				netlogon_creds_cli_check_caps,
1570 				req);
1571 
1572 	return req;
1573 }
1574 
netlogon_creds_cli_check_cleanup(struct tevent_req * req,NTSTATUS status)1575 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1576 					     NTSTATUS status)
1577 {
1578 	struct netlogon_creds_cli_check_state *state =
1579 		tevent_req_data(req,
1580 		struct netlogon_creds_cli_check_state);
1581 
1582 	if (state->creds == NULL) {
1583 		return;
1584 	}
1585 
1586 	if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1587 	    !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1588 	    !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1589 	    !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1590 	    !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1591 		TALLOC_FREE(state->creds);
1592 		return;
1593 	}
1594 
1595 	netlogon_creds_cli_delete_lck(state->context);
1596 	TALLOC_FREE(state->creds);
1597 }
1598 
netlogon_creds_cli_check_caps(struct tevent_req * subreq)1599 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1600 {
1601 	struct tevent_req *req =
1602 		tevent_req_callback_data(subreq,
1603 		struct tevent_req);
1604 	struct netlogon_creds_cli_check_state *state =
1605 		tevent_req_data(req,
1606 		struct netlogon_creds_cli_check_state);
1607 	NTSTATUS status;
1608 	NTSTATUS result;
1609 	bool ok;
1610 
1611 	status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1612 						       &result);
1613 	TALLOC_FREE(subreq);
1614 	if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1615 		/*
1616 		 * Note that the negotiated flags are already checked
1617 		 * for our required flags after the ServerAuthenticate3/2 call.
1618 		 */
1619 		uint32_t negotiated = state->creds->negotiate_flags;
1620 
1621 		if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1622 			/*
1623 			 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1624 			 * already, we expect this to work!
1625 			 */
1626 			status = NT_STATUS_DOWNGRADE_DETECTED;
1627 			tevent_req_nterror(req, status);
1628 			netlogon_creds_cli_check_cleanup(req, status);
1629 			return;
1630 		}
1631 
1632 		if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1633 			/*
1634 			 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1635 			 * we expect this to work at least as far as the
1636 			 * NOT_SUPPORTED error handled below!
1637 			 *
1638 			 * NT 4.0 and Old Samba servers are not
1639 			 * allowed without "require strong key = no"
1640 			 */
1641 			status = NT_STATUS_DOWNGRADE_DETECTED;
1642 			tevent_req_nterror(req, status);
1643 			netlogon_creds_cli_check_cleanup(req, status);
1644 			return;
1645 		}
1646 
1647 		/*
1648 		 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1649 		 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1650 		 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1651 		 *
1652 		 * This is needed against NT 4.0 and old Samba servers.
1653 		 *
1654 		 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1655 		 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1656 		 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1657 		 * with the next request as the sequence number processing
1658 		 * gets out of sync.
1659 		 */
1660 		netlogon_creds_cli_check_cleanup(req, status);
1661 		tevent_req_done(req);
1662 		return;
1663 	}
1664 	if (tevent_req_nterror(req, status)) {
1665 		netlogon_creds_cli_check_cleanup(req, status);
1666 		return;
1667 	}
1668 
1669 	if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1670 		/*
1671 		 * Note that the negotiated flags are already checked
1672 		 * for our required flags after the ServerAuthenticate3/2 call.
1673 		 */
1674 		uint32_t negotiated = state->creds->negotiate_flags;
1675 
1676 		if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1677 			/*
1678 			 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1679 			 * already, we expect this to work!
1680 			 */
1681 			status = NT_STATUS_DOWNGRADE_DETECTED;
1682 			tevent_req_nterror(req, status);
1683 			netlogon_creds_cli_check_cleanup(req, status);
1684 			return;
1685 		}
1686 
1687 		/*
1688 		 * This is ok, the server does not support
1689 		 * NETLOGON_NEG_SUPPORTS_AES.
1690 		 *
1691 		 * netr_LogonGetCapabilities() was
1692 		 * netr_LogonDummyRoutine1() before
1693 		 * NETLOGON_NEG_SUPPORTS_AES was invented.
1694 		 */
1695 		netlogon_creds_cli_check_cleanup(req, result);
1696 		tevent_req_done(req);
1697 		return;
1698 	}
1699 
1700 	ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
1701 	if (!ok) {
1702 		status = NT_STATUS_ACCESS_DENIED;
1703 		tevent_req_nterror(req, status);
1704 		netlogon_creds_cli_check_cleanup(req, status);
1705 		return;
1706 	}
1707 
1708 	if (tevent_req_nterror(req, result)) {
1709 		netlogon_creds_cli_check_cleanup(req, result);
1710 		return;
1711 	}
1712 
1713 	if (state->caps.server_capabilities != state->creds->negotiate_flags) {
1714 		status = NT_STATUS_DOWNGRADE_DETECTED;
1715 		tevent_req_nterror(req, status);
1716 		netlogon_creds_cli_check_cleanup(req, status);
1717 		return;
1718 	}
1719 
1720 	/*
1721 	 * This is the key check that makes this check secure.  If we
1722 	 * get OK here (rather than NOT_SUPPORTED), then the server
1723 	 * did support AES. If the server only proposed STRONG_KEYS
1724 	 * and not AES, then it should have failed with
1725 	 * NOT_IMPLEMENTED. We always send AES as a client, so the
1726 	 * server should always have returned it.
1727 	 */
1728 	if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1729 		status = NT_STATUS_DOWNGRADE_DETECTED;
1730 		tevent_req_nterror(req, status);
1731 		netlogon_creds_cli_check_cleanup(req, status);
1732 		return;
1733 	}
1734 
1735 	status = netlogon_creds_cli_store_internal(state->context,
1736 						   state->creds);
1737 	if (tevent_req_nterror(req, status)) {
1738 		return;
1739 	}
1740 
1741 	tevent_req_done(req);
1742 }
1743 
netlogon_creds_cli_check_recv(struct tevent_req * req,union netr_Capabilities * capabilities)1744 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
1745 				       union netr_Capabilities *capabilities)
1746 {
1747 	struct netlogon_creds_cli_check_state *state = tevent_req_data(
1748 		req, struct netlogon_creds_cli_check_state);
1749 	NTSTATUS status;
1750 
1751 	if (tevent_req_is_nterror(req, &status)) {
1752 		netlogon_creds_cli_check_cleanup(req, status);
1753 		tevent_req_received(req);
1754 		return status;
1755 	}
1756 
1757 	if (capabilities != NULL) {
1758 		*capabilities = state->caps;
1759 	}
1760 
1761 	tevent_req_received(req);
1762 	return NT_STATUS_OK;
1763 }
1764 
netlogon_creds_cli_check(struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b,union netr_Capabilities * capabilities)1765 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1766 				  struct dcerpc_binding_handle *b,
1767 				  union netr_Capabilities *capabilities)
1768 {
1769 	TALLOC_CTX *frame = talloc_stackframe();
1770 	struct tevent_context *ev;
1771 	struct tevent_req *req;
1772 	NTSTATUS status = NT_STATUS_NO_MEMORY;
1773 
1774 	ev = samba_tevent_context_init(frame);
1775 	if (ev == NULL) {
1776 		goto fail;
1777 	}
1778 	req = netlogon_creds_cli_check_send(frame, ev, context, b);
1779 	if (req == NULL) {
1780 		goto fail;
1781 	}
1782 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1783 		goto fail;
1784 	}
1785 	status = netlogon_creds_cli_check_recv(req, capabilities);
1786  fail:
1787 	TALLOC_FREE(frame);
1788 	return status;
1789 }
1790 
1791 struct netlogon_creds_cli_ServerPasswordSet_state {
1792 	struct tevent_context *ev;
1793 	struct netlogon_creds_cli_context *context;
1794 	struct dcerpc_binding_handle *binding_handle;
1795 	uint32_t old_timeout;
1796 
1797 	char *srv_name_slash;
1798 	enum dcerpc_AuthType auth_type;
1799 	enum dcerpc_AuthLevel auth_level;
1800 
1801 	struct samr_CryptPassword samr_crypt_password;
1802 	struct netr_CryptPassword netr_crypt_password;
1803 	struct samr_Password samr_password;
1804 
1805 	struct netlogon_creds_CredentialState *creds;
1806 	struct netlogon_creds_CredentialState tmp_creds;
1807 	struct netr_Authenticator req_auth;
1808 	struct netr_Authenticator rep_auth;
1809 };
1810 
1811 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1812 						     NTSTATUS status);
1813 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1814 
netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b,const DATA_BLOB * new_password,const uint32_t * new_version)1815 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1816 				struct tevent_context *ev,
1817 				struct netlogon_creds_cli_context *context,
1818 				struct dcerpc_binding_handle *b,
1819 				const DATA_BLOB *new_password,
1820 				const uint32_t *new_version)
1821 {
1822 	struct tevent_req *req;
1823 	struct netlogon_creds_cli_ServerPasswordSet_state *state;
1824 	struct tevent_req *subreq;
1825 	bool ok;
1826 
1827 	req = tevent_req_create(mem_ctx, &state,
1828 				struct netlogon_creds_cli_ServerPasswordSet_state);
1829 	if (req == NULL) {
1830 		return NULL;
1831 	}
1832 
1833 	state->ev = ev;
1834 	state->context = context;
1835 	state->binding_handle = b;
1836 
1837 	if (new_password->length < 14) {
1838 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1839 		return tevent_req_post(req, ev);
1840 	}
1841 
1842 	/*
1843 	 * netr_ServerPasswordSet
1844 	 */
1845 	mdfour(state->samr_password.hash, new_password->data, new_password->length);
1846 
1847 	/*
1848 	 * netr_ServerPasswordSet2
1849 	 */
1850 	ok = set_pw_in_buffer(state->samr_crypt_password.data,
1851 			      new_password);
1852 	if (!ok) {
1853 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1854 		return tevent_req_post(req, ev);
1855 	}
1856 
1857 	if (new_version != NULL) {
1858 		struct NL_PASSWORD_VERSION version;
1859 		uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1860 		uint32_t ofs = 512 - len;
1861 		uint8_t *p;
1862 
1863 		if (len > 500) {
1864 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1865 			return tevent_req_post(req, ev);
1866 		}
1867 		ofs -= 12;
1868 
1869 		version.ReservedField = 0;
1870 		version.PasswordVersionNumber = *new_version;
1871 		version.PasswordVersionPresent =
1872 			NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1873 
1874 		p = state->samr_crypt_password.data + ofs;
1875 		SIVAL(p, 0, version.ReservedField);
1876 		SIVAL(p, 4, version.PasswordVersionNumber);
1877 		SIVAL(p, 8, version.PasswordVersionPresent);
1878 	}
1879 
1880 	state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1881 						context->server.computer);
1882 	if (tevent_req_nomem(state->srv_name_slash, req)) {
1883 		return tevent_req_post(req, ev);
1884 	}
1885 
1886 	dcerpc_binding_handle_auth_info(state->binding_handle,
1887 					&state->auth_type,
1888 					&state->auth_level);
1889 
1890 	subreq = netlogon_creds_cli_lock_send(state, state->ev,
1891 					      state->context);
1892 	if (tevent_req_nomem(subreq, req)) {
1893 		return tevent_req_post(req, ev);
1894 	}
1895 
1896 	tevent_req_set_callback(subreq,
1897 				netlogon_creds_cli_ServerPasswordSet_locked,
1898 				req);
1899 
1900 	return req;
1901 }
1902 
netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req * req,NTSTATUS status)1903 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1904 							 NTSTATUS status)
1905 {
1906 	struct netlogon_creds_cli_ServerPasswordSet_state *state =
1907 		tevent_req_data(req,
1908 		struct netlogon_creds_cli_ServerPasswordSet_state);
1909 
1910 	if (state->creds == NULL) {
1911 		return;
1912 	}
1913 
1914 	dcerpc_binding_handle_set_timeout(state->binding_handle,
1915 					  state->old_timeout);
1916 
1917 	if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1918 	    !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1919 	    !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1920 	    !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1921 	    !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1922 		TALLOC_FREE(state->creds);
1923 		return;
1924 	}
1925 
1926 	netlogon_creds_cli_delete(state->context, state->creds);
1927 	TALLOC_FREE(state->creds);
1928 }
1929 
1930 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1931 
netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req * subreq)1932 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1933 {
1934 	struct tevent_req *req =
1935 		tevent_req_callback_data(subreq,
1936 		struct tevent_req);
1937 	struct netlogon_creds_cli_ServerPasswordSet_state *state =
1938 		tevent_req_data(req,
1939 		struct netlogon_creds_cli_ServerPasswordSet_state);
1940 	NTSTATUS status;
1941 
1942 	status = netlogon_creds_cli_lock_recv(subreq, state,
1943 					      &state->creds);
1944 	TALLOC_FREE(subreq);
1945 	if (tevent_req_nterror(req, status)) {
1946 		return;
1947 	}
1948 
1949 	if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1950 		switch (state->auth_level) {
1951 		case DCERPC_AUTH_LEVEL_INTEGRITY:
1952 		case DCERPC_AUTH_LEVEL_PRIVACY:
1953 			break;
1954 		default:
1955 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1956 			return;
1957 		}
1958 	} else {
1959 		uint32_t tmp = state->creds->negotiate_flags;
1960 
1961 		if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1962 			/*
1963 			 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1964 			 * it should be used, which means
1965 			 * we had a chance to verify no downgrade
1966 			 * happened.
1967 			 *
1968 			 * This relies on netlogon_creds_cli_check*
1969 			 * being called before, as first request after
1970 			 * the DCERPC bind.
1971 			 */
1972 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1973 			return;
1974 		}
1975 	}
1976 
1977 	state->old_timeout = dcerpc_binding_handle_set_timeout(
1978 				state->binding_handle, 600000);
1979 
1980 	/*
1981 	 * we defer all callbacks in order to cleanup
1982 	 * the database record.
1983 	 */
1984 	tevent_req_defer_callback(req, state->ev);
1985 
1986 	state->tmp_creds = *state->creds;
1987 	status = netlogon_creds_client_authenticator(&state->tmp_creds,
1988 						     &state->req_auth);
1989 	if (tevent_req_nterror(req, status)) {
1990 		return;
1991 	}
1992 	ZERO_STRUCT(state->rep_auth);
1993 
1994 	if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1995 
1996 		if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1997 			status = netlogon_creds_aes_encrypt(&state->tmp_creds,
1998 							    state->samr_crypt_password.data,
1999 							    516);
2000 			if (tevent_req_nterror(req, status)) {
2001 				netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2002 				return;
2003 			}
2004 		} else {
2005 			status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
2006 							      state->samr_crypt_password.data,
2007 							      516);
2008 			if (tevent_req_nterror(req, status)) {
2009 				netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2010 				return;
2011 			}
2012 		}
2013 
2014 		memcpy(state->netr_crypt_password.data,
2015 		       state->samr_crypt_password.data, 512);
2016 		state->netr_crypt_password.length =
2017 			IVAL(state->samr_crypt_password.data, 512);
2018 
2019 		subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
2020 					state->binding_handle,
2021 					state->srv_name_slash,
2022 					state->tmp_creds.account_name,
2023 					state->tmp_creds.secure_channel_type,
2024 					state->tmp_creds.computer_name,
2025 					&state->req_auth,
2026 					&state->rep_auth,
2027 					&state->netr_crypt_password);
2028 		if (tevent_req_nomem(subreq, req)) {
2029 			status = NT_STATUS_NO_MEMORY;
2030 			netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2031 			return;
2032 		}
2033 	} else {
2034 		status = netlogon_creds_des_encrypt(&state->tmp_creds,
2035 						    &state->samr_password);
2036 		if (tevent_req_nterror(req, status)) {
2037 			netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2038 			return;
2039 		}
2040 
2041 		subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2042 					state->binding_handle,
2043 					state->srv_name_slash,
2044 					state->tmp_creds.account_name,
2045 					state->tmp_creds.secure_channel_type,
2046 					state->tmp_creds.computer_name,
2047 					&state->req_auth,
2048 					&state->rep_auth,
2049 					&state->samr_password);
2050 		if (tevent_req_nomem(subreq, req)) {
2051 			status = NT_STATUS_NO_MEMORY;
2052 			netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2053 			return;
2054 		}
2055 	}
2056 
2057 	tevent_req_set_callback(subreq,
2058 				netlogon_creds_cli_ServerPasswordSet_done,
2059 				req);
2060 }
2061 
netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req * subreq)2062 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2063 {
2064 	struct tevent_req *req =
2065 		tevent_req_callback_data(subreq,
2066 		struct tevent_req);
2067 	struct netlogon_creds_cli_ServerPasswordSet_state *state =
2068 		tevent_req_data(req,
2069 		struct netlogon_creds_cli_ServerPasswordSet_state);
2070 	NTSTATUS status;
2071 	NTSTATUS result;
2072 	bool ok;
2073 
2074 	if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2075 		status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2076 							     &result);
2077 		TALLOC_FREE(subreq);
2078 		if (tevent_req_nterror(req, status)) {
2079 			netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2080 			return;
2081 		}
2082 	} else {
2083 		status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2084 							    &result);
2085 		TALLOC_FREE(subreq);
2086 		if (tevent_req_nterror(req, status)) {
2087 			netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2088 			return;
2089 		}
2090 	}
2091 
2092 	ok = netlogon_creds_client_check(&state->tmp_creds,
2093 					 &state->rep_auth.cred);
2094 	if (!ok) {
2095 		status = NT_STATUS_ACCESS_DENIED;
2096 		tevent_req_nterror(req, status);
2097 		netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2098 		return;
2099 	}
2100 
2101 	if (tevent_req_nterror(req, result)) {
2102 		netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2103 		return;
2104 	}
2105 
2106 	dcerpc_binding_handle_set_timeout(state->binding_handle,
2107 					  state->old_timeout);
2108 
2109 	*state->creds = state->tmp_creds;
2110 	status = netlogon_creds_cli_store(state->context,
2111 					  state->creds);
2112 	TALLOC_FREE(state->creds);
2113 	if (tevent_req_nterror(req, status)) {
2114 		netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2115 		return;
2116 	}
2117 
2118 	tevent_req_done(req);
2119 }
2120 
netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req * req)2121 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2122 {
2123 	NTSTATUS status;
2124 
2125 	if (tevent_req_is_nterror(req, &status)) {
2126 		netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2127 		tevent_req_received(req);
2128 		return status;
2129 	}
2130 
2131 	tevent_req_received(req);
2132 	return NT_STATUS_OK;
2133 }
2134 
netlogon_creds_cli_ServerPasswordSet(struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b,const DATA_BLOB * new_password,const uint32_t * new_version)2135 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2136 				struct netlogon_creds_cli_context *context,
2137 				struct dcerpc_binding_handle *b,
2138 				const DATA_BLOB *new_password,
2139 				const uint32_t *new_version)
2140 {
2141 	TALLOC_CTX *frame = talloc_stackframe();
2142 	struct tevent_context *ev;
2143 	struct tevent_req *req;
2144 	NTSTATUS status = NT_STATUS_NO_MEMORY;
2145 
2146 	ev = samba_tevent_context_init(frame);
2147 	if (ev == NULL) {
2148 		goto fail;
2149 	}
2150 	req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2151 							new_password,
2152 							new_version);
2153 	if (req == NULL) {
2154 		goto fail;
2155 	}
2156 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2157 		goto fail;
2158 	}
2159 	status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2160  fail:
2161 	TALLOC_FREE(frame);
2162 	return status;
2163 }
2164 
2165 struct netlogon_creds_cli_LogonSamLogon_state {
2166 	struct tevent_context *ev;
2167 	struct netlogon_creds_cli_context *context;
2168 	struct dcerpc_binding_handle *binding_handle;
2169 
2170 	char *srv_name_slash;
2171 
2172 	enum netr_LogonInfoClass logon_level;
2173 	const union netr_LogonLevel *const_logon;
2174 	union netr_LogonLevel *logon;
2175 	uint32_t flags;
2176 
2177 	uint16_t validation_level;
2178 	union netr_Validation *validation;
2179 	uint8_t authoritative;
2180 
2181 	/*
2182 	 * do we need encryption at the application layer?
2183 	 */
2184 	bool user_encrypt;
2185 	bool try_logon_ex;
2186 	bool try_validation6;
2187 
2188 	/*
2189 	 * the read only credentials before we started the operation
2190 	 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2191 	 */
2192 	struct netlogon_creds_CredentialState *ro_creds;
2193 
2194 	/*
2195 	 * The (locked) credentials used for the credential chain
2196 	 * used for netr_LogonSamLogonWithFlags() or
2197 	 * netr_LogonSamLogonWith().
2198 	 */
2199 	struct netlogon_creds_CredentialState *lk_creds;
2200 
2201 	/*
2202 	 * While we have locked the global credentials (lk_creds above)
2203 	 * we operate an a temporary copy, because a server
2204 	 * may not support netr_LogonSamLogonWithFlags() and
2205 	 * didn't process our netr_Authenticator, so we need to
2206 	 * restart from lk_creds.
2207 	 */
2208 	struct netlogon_creds_CredentialState tmp_creds;
2209 	struct netr_Authenticator req_auth;
2210 	struct netr_Authenticator rep_auth;
2211 };
2212 
2213 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2214 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2215 						     NTSTATUS status);
2216 
netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b,enum netr_LogonInfoClass logon_level,const union netr_LogonLevel * logon,uint32_t flags)2217 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2218 				struct tevent_context *ev,
2219 				struct netlogon_creds_cli_context *context,
2220 				struct dcerpc_binding_handle *b,
2221 				enum netr_LogonInfoClass logon_level,
2222 				const union netr_LogonLevel *logon,
2223 				uint32_t flags)
2224 {
2225 	struct tevent_req *req;
2226 	struct netlogon_creds_cli_LogonSamLogon_state *state;
2227 
2228 	req = tevent_req_create(mem_ctx, &state,
2229 				struct netlogon_creds_cli_LogonSamLogon_state);
2230 	if (req == NULL) {
2231 		return NULL;
2232 	}
2233 
2234 	state->ev = ev;
2235 	state->context = context;
2236 	state->binding_handle = b;
2237 
2238 	state->logon_level = logon_level;
2239 	state->const_logon = logon;
2240 	state->flags = flags;
2241 
2242 	state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2243 						context->server.computer);
2244 	if (tevent_req_nomem(state->srv_name_slash, req)) {
2245 		return tevent_req_post(req, ev);
2246 	}
2247 
2248 	switch (logon_level) {
2249 	case NetlogonInteractiveInformation:
2250 	case NetlogonInteractiveTransitiveInformation:
2251 	case NetlogonServiceInformation:
2252 	case NetlogonServiceTransitiveInformation:
2253 	case NetlogonGenericInformation:
2254 		state->user_encrypt = true;
2255 		break;
2256 
2257 	case NetlogonNetworkInformation:
2258 	case NetlogonNetworkTransitiveInformation:
2259 		break;
2260 	}
2261 
2262 	state->validation = talloc_zero(state, union netr_Validation);
2263 	if (tevent_req_nomem(state->validation, req)) {
2264 		return tevent_req_post(req, ev);
2265 	}
2266 
2267 	netlogon_creds_cli_LogonSamLogon_start(req);
2268 	if (!tevent_req_is_in_progress(req)) {
2269 		return tevent_req_post(req, ev);
2270 	}
2271 
2272 	/*
2273 	 * we defer all callbacks in order to cleanup
2274 	 * the database record.
2275 	 */
2276 	tevent_req_defer_callback(req, state->ev);
2277 	return req;
2278 }
2279 
netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req * req,NTSTATUS status)2280 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2281 						     NTSTATUS status)
2282 {
2283 	struct netlogon_creds_cli_LogonSamLogon_state *state =
2284 		tevent_req_data(req,
2285 		struct netlogon_creds_cli_LogonSamLogon_state);
2286 
2287 	if (state->lk_creds == NULL) {
2288 		return;
2289 	}
2290 
2291 	if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2292 		/*
2293 		 * This is a hack to recover from a bug in old
2294 		 * Samba servers, when LogonSamLogonEx() fails:
2295 		 *
2296 		 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2297 		 *
2298 		 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2299 		 *
2300 		 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2301 		 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2302 		 * If the sign/seal check fails.
2303 		 *
2304 		 * In that case we need to cleanup the netlogon session.
2305 		 *
2306 		 * It's the job of the caller to disconnect the current
2307 		 * connection, if netlogon_creds_cli_LogonSamLogon()
2308 		 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2309 		 */
2310 		if (!state->context->server.try_logon_with) {
2311 			status = NT_STATUS_NETWORK_ACCESS_DENIED;
2312 		}
2313 	}
2314 
2315 	if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2316 	    !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2317 	    !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2318 	    !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2319 	    !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2320 		TALLOC_FREE(state->lk_creds);
2321 		return;
2322 	}
2323 
2324 	netlogon_creds_cli_delete(state->context, state->lk_creds);
2325 	TALLOC_FREE(state->lk_creds);
2326 }
2327 
2328 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2329 
netlogon_creds_cli_LogonSamLogon_start(struct tevent_req * req)2330 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2331 {
2332 	struct netlogon_creds_cli_LogonSamLogon_state *state =
2333 		tevent_req_data(req,
2334 		struct netlogon_creds_cli_LogonSamLogon_state);
2335 	struct tevent_req *subreq;
2336 	NTSTATUS status;
2337 	enum dcerpc_AuthType auth_type;
2338 	enum dcerpc_AuthLevel auth_level;
2339 
2340 	TALLOC_FREE(state->ro_creds);
2341 	TALLOC_FREE(state->logon);
2342 	ZERO_STRUCTP(state->validation);
2343 
2344 	dcerpc_binding_handle_auth_info(state->binding_handle,
2345 					&auth_type, &auth_level);
2346 
2347 	state->try_logon_ex = state->context->server.try_logon_ex;
2348 	state->try_validation6 = state->context->server.try_validation6;
2349 
2350 	if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2351 		state->try_logon_ex = false;
2352 	}
2353 
2354 	if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2355 		state->try_validation6 = false;
2356 	}
2357 
2358 	if (state->try_logon_ex) {
2359 		if (state->try_validation6) {
2360 			state->validation_level = 6;
2361 		} else {
2362 			state->validation_level = 3;
2363 			state->user_encrypt = true;
2364 		}
2365 
2366 		state->logon = netlogon_creds_shallow_copy_logon(state,
2367 							state->logon_level,
2368 							state->const_logon);
2369 		if (tevent_req_nomem(state->logon, req)) {
2370 			status = NT_STATUS_NO_MEMORY;
2371 			netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2372 			return;
2373 		}
2374 
2375 		if (state->user_encrypt) {
2376 			status = netlogon_creds_cli_get(state->context,
2377 							state,
2378 							&state->ro_creds);
2379 			if (!NT_STATUS_IS_OK(status)) {
2380 				status = NT_STATUS_ACCESS_DENIED;
2381 				tevent_req_nterror(req, status);
2382 				netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2383 				return;
2384 			}
2385 
2386 			status = netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2387 								       state->logon_level,
2388 								       state->logon);
2389 			if (!NT_STATUS_IS_OK(status)) {
2390 				status = NT_STATUS_ACCESS_DENIED;
2391 				tevent_req_nterror(req, status);
2392 				netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2393 				return;
2394 			}
2395 		}
2396 
2397 		subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2398 						state->binding_handle,
2399 						state->srv_name_slash,
2400 						state->context->client.computer,
2401 						state->logon_level,
2402 						state->logon,
2403 						state->validation_level,
2404 						state->validation,
2405 						&state->authoritative,
2406 						&state->flags);
2407 		if (tevent_req_nomem(subreq, req)) {
2408 			status = NT_STATUS_NO_MEMORY;
2409 			netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2410 			return;
2411 		}
2412 		tevent_req_set_callback(subreq,
2413 					netlogon_creds_cli_LogonSamLogon_done,
2414 					req);
2415 		return;
2416 	}
2417 
2418 	if (state->lk_creds == NULL) {
2419 		subreq = netlogon_creds_cli_lock_send(state, state->ev,
2420 						      state->context);
2421 		if (tevent_req_nomem(subreq, req)) {
2422 			status = NT_STATUS_NO_MEMORY;
2423 			netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2424 			return;
2425 		}
2426 		tevent_req_set_callback(subreq,
2427 					netlogon_creds_cli_LogonSamLogon_done,
2428 					req);
2429 		return;
2430 	}
2431 
2432 	state->tmp_creds = *state->lk_creds;
2433 	status = netlogon_creds_client_authenticator(&state->tmp_creds,
2434 						     &state->req_auth);
2435 	if (tevent_req_nterror(req, status)) {
2436 		netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2437 		return;
2438 	}
2439 	ZERO_STRUCT(state->rep_auth);
2440 
2441 	state->logon = netlogon_creds_shallow_copy_logon(state,
2442 						state->logon_level,
2443 						state->const_logon);
2444 	if (tevent_req_nomem(state->logon, req)) {
2445 		status = NT_STATUS_NO_MEMORY;
2446 		netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2447 		return;
2448 	}
2449 
2450 	status = netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2451 						       state->logon_level,
2452 						       state->logon);
2453 	if (tevent_req_nterror(req, status)) {
2454 		netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2455 		return;
2456 	}
2457 
2458 	state->validation_level = 3;
2459 
2460 	if (state->context->server.try_logon_with) {
2461 		subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2462 						state->binding_handle,
2463 						state->srv_name_slash,
2464 						state->context->client.computer,
2465 						&state->req_auth,
2466 						&state->rep_auth,
2467 						state->logon_level,
2468 						state->logon,
2469 						state->validation_level,
2470 						state->validation,
2471 						&state->authoritative,
2472 						&state->flags);
2473 		if (tevent_req_nomem(subreq, req)) {
2474 			status = NT_STATUS_NO_MEMORY;
2475 			netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2476 			return;
2477 		}
2478 	} else {
2479 		state->flags = 0;
2480 
2481 		subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2482 						state->binding_handle,
2483 						state->srv_name_slash,
2484 						state->context->client.computer,
2485 						&state->req_auth,
2486 						&state->rep_auth,
2487 						state->logon_level,
2488 						state->logon,
2489 						state->validation_level,
2490 						state->validation,
2491 						&state->authoritative);
2492 		if (tevent_req_nomem(subreq, req)) {
2493 			status = NT_STATUS_NO_MEMORY;
2494 			netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2495 			return;
2496 		}
2497 	}
2498 
2499 	tevent_req_set_callback(subreq,
2500 				netlogon_creds_cli_LogonSamLogon_done,
2501 				req);
2502 }
2503 
netlogon_creds_cli_LogonSamLogon_done(struct tevent_req * subreq)2504 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2505 {
2506 	struct tevent_req *req =
2507 		tevent_req_callback_data(subreq,
2508 		struct tevent_req);
2509 	struct netlogon_creds_cli_LogonSamLogon_state *state =
2510 		tevent_req_data(req,
2511 		struct netlogon_creds_cli_LogonSamLogon_state);
2512 	NTSTATUS status;
2513 	NTSTATUS result;
2514 	bool ok;
2515 
2516 	if (state->try_logon_ex) {
2517 		status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2518 							  state->validation,
2519 							  &result);
2520 		TALLOC_FREE(subreq);
2521 		if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2522 			state->context->server.try_validation6 = false;
2523 			state->context->server.try_logon_ex = false;
2524 			netlogon_creds_cli_LogonSamLogon_start(req);
2525 			return;
2526 		}
2527 		if (tevent_req_nterror(req, status)) {
2528 			netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2529 			return;
2530 		}
2531 
2532 		if ((state->validation_level == 6) &&
2533 		    (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2534 		     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2535 		     NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2536 		{
2537 			state->context->server.try_validation6 = false;
2538 			netlogon_creds_cli_LogonSamLogon_start(req);
2539 			return;
2540 		}
2541 
2542 		if (tevent_req_nterror(req, result)) {
2543 			netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2544 			return;
2545 		}
2546 
2547 		if (state->ro_creds == NULL) {
2548 			tevent_req_done(req);
2549 			return;
2550 		}
2551 
2552 		ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2553 		if (!ok) {
2554 			/*
2555 			 * We got a race, lets retry with on authenticator
2556 			 * protection.
2557 			 *
2558 			 * netlogon_creds_cli_LogonSamLogon_start()
2559 			 * will TALLOC_FREE(state->ro_creds);
2560 			 */
2561 			state->try_logon_ex = false;
2562 			netlogon_creds_cli_LogonSamLogon_start(req);
2563 			return;
2564 		}
2565 
2566 		status = netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2567 								    state->validation_level,
2568 								    state->validation);
2569 		if (tevent_req_nterror(req, status)) {
2570 			netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2571 			return;
2572 		}
2573 
2574 		tevent_req_done(req);
2575 		return;
2576 	}
2577 
2578 	if (state->lk_creds == NULL) {
2579 		status = netlogon_creds_cli_lock_recv(subreq, state,
2580 						      &state->lk_creds);
2581 		TALLOC_FREE(subreq);
2582 		if (tevent_req_nterror(req, status)) {
2583 			netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2584 			return;
2585 		}
2586 
2587 		netlogon_creds_cli_LogonSamLogon_start(req);
2588 		return;
2589 	}
2590 
2591 	if (state->context->server.try_logon_with) {
2592 		status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2593 								 state->validation,
2594 								 &result);
2595 		TALLOC_FREE(subreq);
2596 		if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2597 			state->context->server.try_logon_with = false;
2598 			netlogon_creds_cli_LogonSamLogon_start(req);
2599 			return;
2600 		}
2601 		if (tevent_req_nterror(req, status)) {
2602 			netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2603 			return;
2604 		}
2605 	} else {
2606 		status = dcerpc_netr_LogonSamLogon_recv(subreq,
2607 							state->validation,
2608 							&result);
2609 		TALLOC_FREE(subreq);
2610 		if (tevent_req_nterror(req, status)) {
2611 			netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2612 			return;
2613 		}
2614 	}
2615 
2616 	ok = netlogon_creds_client_check(&state->tmp_creds,
2617 					 &state->rep_auth.cred);
2618 	if (!ok) {
2619 		status = NT_STATUS_ACCESS_DENIED;
2620 		tevent_req_nterror(req, status);
2621 		netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2622 		return;
2623 	}
2624 
2625 	*state->lk_creds = state->tmp_creds;
2626 	status = netlogon_creds_cli_store(state->context,
2627 					  state->lk_creds);
2628 	TALLOC_FREE(state->lk_creds);
2629 
2630 	if (tevent_req_nterror(req, status)) {
2631 		netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2632 		return;
2633 	}
2634 
2635 	if (tevent_req_nterror(req, result)) {
2636 		netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2637 		return;
2638 	}
2639 
2640 	status = netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2641 							    state->validation_level,
2642 							    state->validation);
2643 	if (tevent_req_nterror(req, status)) {
2644 		netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2645 		return;
2646 	}
2647 
2648 	tevent_req_done(req);
2649 }
2650 
netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,uint16_t * validation_level,union netr_Validation ** validation,uint8_t * authoritative,uint32_t * flags)2651 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2652 					TALLOC_CTX *mem_ctx,
2653 					uint16_t *validation_level,
2654 					union netr_Validation **validation,
2655 					uint8_t *authoritative,
2656 					uint32_t *flags)
2657 {
2658 	struct netlogon_creds_cli_LogonSamLogon_state *state =
2659 		tevent_req_data(req,
2660 		struct netlogon_creds_cli_LogonSamLogon_state);
2661 	NTSTATUS status;
2662 
2663 	/* authoritative is also returned on error */
2664 	*authoritative = state->authoritative;
2665 
2666 	if (tevent_req_is_nterror(req, &status)) {
2667 		netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2668 		tevent_req_received(req);
2669 		return status;
2670 	}
2671 
2672 	*validation_level = state->validation_level;
2673 	*validation = talloc_move(mem_ctx, &state->validation);
2674 	*flags = state->flags;
2675 
2676 	tevent_req_received(req);
2677 	return NT_STATUS_OK;
2678 }
2679 
netlogon_creds_cli_LogonSamLogon(struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b,enum netr_LogonInfoClass logon_level,const union netr_LogonLevel * logon,TALLOC_CTX * mem_ctx,uint16_t * validation_level,union netr_Validation ** validation,uint8_t * authoritative,uint32_t * flags)2680 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2681 				struct netlogon_creds_cli_context *context,
2682 				struct dcerpc_binding_handle *b,
2683 				enum netr_LogonInfoClass logon_level,
2684 				const union netr_LogonLevel *logon,
2685 				TALLOC_CTX *mem_ctx,
2686 				uint16_t *validation_level,
2687 				union netr_Validation **validation,
2688 				uint8_t *authoritative,
2689 				uint32_t *flags)
2690 {
2691 	TALLOC_CTX *frame = talloc_stackframe();
2692 	struct tevent_context *ev;
2693 	struct tevent_req *req;
2694 	NTSTATUS status = NT_STATUS_NO_MEMORY;
2695 
2696 	ev = samba_tevent_context_init(frame);
2697 	if (ev == NULL) {
2698 		goto fail;
2699 	}
2700 	req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2701 						    logon_level, logon,
2702 						    *flags);
2703 	if (req == NULL) {
2704 		goto fail;
2705 	}
2706 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2707 		goto fail;
2708 	}
2709 	status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2710 						       validation_level,
2711 						       validation,
2712 						       authoritative,
2713 						       flags);
2714  fail:
2715 	TALLOC_FREE(frame);
2716 	return status;
2717 }
2718 
2719 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2720 	struct tevent_context *ev;
2721 	struct netlogon_creds_cli_context *context;
2722 	struct dcerpc_binding_handle *binding_handle;
2723 
2724 	char *srv_name_slash;
2725 	enum dcerpc_AuthType auth_type;
2726 	enum dcerpc_AuthLevel auth_level;
2727 
2728 	const char *site_name;
2729 	uint32_t dns_ttl;
2730 	struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2731 
2732 	struct netlogon_creds_CredentialState *creds;
2733 	struct netlogon_creds_CredentialState tmp_creds;
2734 	struct netr_Authenticator req_auth;
2735 	struct netr_Authenticator rep_auth;
2736 };
2737 
2738 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2739 						     NTSTATUS status);
2740 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2741 
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b,const char * site_name,uint32_t dns_ttl,struct NL_DNS_NAME_INFO_ARRAY * dns_names)2742 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2743 									     struct tevent_context *ev,
2744 									     struct netlogon_creds_cli_context *context,
2745 									     struct dcerpc_binding_handle *b,
2746 									     const char *site_name,
2747 									     uint32_t dns_ttl,
2748 									     struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2749 {
2750 	struct tevent_req *req;
2751 	struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2752 	struct tevent_req *subreq;
2753 
2754 	req = tevent_req_create(mem_ctx, &state,
2755 				struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2756 	if (req == NULL) {
2757 		return NULL;
2758 	}
2759 
2760 	state->ev = ev;
2761 	state->context = context;
2762 	state->binding_handle = b;
2763 
2764 	state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2765 						context->server.computer);
2766 	if (tevent_req_nomem(state->srv_name_slash, req)) {
2767 		return tevent_req_post(req, ev);
2768 	}
2769 
2770 	state->site_name = site_name;
2771 	state->dns_ttl = dns_ttl;
2772 	state->dns_names = dns_names;
2773 
2774 	dcerpc_binding_handle_auth_info(state->binding_handle,
2775 					&state->auth_type,
2776 					&state->auth_level);
2777 
2778 	subreq = netlogon_creds_cli_lock_send(state, state->ev,
2779 					      state->context);
2780 	if (tevent_req_nomem(subreq, req)) {
2781 		return tevent_req_post(req, ev);
2782 	}
2783 
2784 	tevent_req_set_callback(subreq,
2785 				netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2786 				req);
2787 
2788 	return req;
2789 }
2790 
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req * req,NTSTATUS status)2791 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2792 							 NTSTATUS status)
2793 {
2794 	struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2795 		tevent_req_data(req,
2796 		struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2797 
2798 	if (state->creds == NULL) {
2799 		return;
2800 	}
2801 
2802 	if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2803 	    !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2804 	    !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2805 	    !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2806 	    !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2807 		TALLOC_FREE(state->creds);
2808 		return;
2809 	}
2810 
2811 	netlogon_creds_cli_delete(state->context, state->creds);
2812 	TALLOC_FREE(state->creds);
2813 }
2814 
2815 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2816 
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req * subreq)2817 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2818 {
2819 	struct tevent_req *req =
2820 		tevent_req_callback_data(subreq,
2821 		struct tevent_req);
2822 	struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2823 		tevent_req_data(req,
2824 		struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2825 	NTSTATUS status;
2826 
2827 	status = netlogon_creds_cli_lock_recv(subreq, state,
2828 					      &state->creds);
2829 	TALLOC_FREE(subreq);
2830 	if (tevent_req_nterror(req, status)) {
2831 		return;
2832 	}
2833 
2834 	if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2835 		switch (state->auth_level) {
2836 		case DCERPC_AUTH_LEVEL_INTEGRITY:
2837 		case DCERPC_AUTH_LEVEL_PRIVACY:
2838 			break;
2839 		default:
2840 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2841 			return;
2842 		}
2843 	} else {
2844 		uint32_t tmp = state->creds->negotiate_flags;
2845 
2846 		if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2847 			/*
2848 			 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2849 			 * it should be used, which means
2850 			 * we had a chance to verify no downgrade
2851 			 * happened.
2852 			 *
2853 			 * This relies on netlogon_creds_cli_check*
2854 			 * being called before, as first request after
2855 			 * the DCERPC bind.
2856 			 */
2857 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2858 			return;
2859 		}
2860 	}
2861 
2862 	/*
2863 	 * we defer all callbacks in order to cleanup
2864 	 * the database record.
2865 	 */
2866 	tevent_req_defer_callback(req, state->ev);
2867 
2868 	state->tmp_creds = *state->creds;
2869 	status = netlogon_creds_client_authenticator(&state->tmp_creds,
2870 						     &state->req_auth);
2871 	if (tevent_req_nterror(req, status)) {
2872 		return;
2873 	}
2874 	ZERO_STRUCT(state->rep_auth);
2875 
2876 	subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2877 								    state->binding_handle,
2878 								    state->srv_name_slash,
2879 								    state->tmp_creds.computer_name,
2880 								    &state->req_auth,
2881 								    &state->rep_auth,
2882 								    state->site_name,
2883 								    state->dns_ttl,
2884 								    state->dns_names);
2885 	if (tevent_req_nomem(subreq, req)) {
2886 		status = NT_STATUS_NO_MEMORY;
2887 		netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2888 		return;
2889 	}
2890 
2891 	tevent_req_set_callback(subreq,
2892 				netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2893 				req);
2894 }
2895 
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req * subreq)2896 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2897 {
2898 	struct tevent_req *req =
2899 		tevent_req_callback_data(subreq,
2900 		struct tevent_req);
2901 	struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2902 		tevent_req_data(req,
2903 		struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2904 	NTSTATUS status;
2905 	NTSTATUS result;
2906 	bool ok;
2907 
2908 	/*
2909 	 * We use state->dns_names as the memory context, as this is
2910 	 * the only in/out variable and it has been overwritten by the
2911 	 * out parameter from the server.
2912 	 *
2913 	 * We need to preserve the return value until the caller can use it.
2914 	 */
2915 	status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2916 								    &result);
2917 	TALLOC_FREE(subreq);
2918 	if (tevent_req_nterror(req, status)) {
2919 		netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2920 		return;
2921 	}
2922 
2923 	ok = netlogon_creds_client_check(&state->tmp_creds,
2924 					 &state->rep_auth.cred);
2925 	if (!ok) {
2926 		status = NT_STATUS_ACCESS_DENIED;
2927 		tevent_req_nterror(req, status);
2928 		netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2929 		return;
2930 	}
2931 
2932 	*state->creds = state->tmp_creds;
2933 	status = netlogon_creds_cli_store(state->context,
2934 					  state->creds);
2935 	TALLOC_FREE(state->creds);
2936 
2937 	if (tevent_req_nterror(req, status)) {
2938 		netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2939 		return;
2940 	}
2941 
2942 	if (tevent_req_nterror(req, result)) {
2943 		netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2944 		return;
2945 	}
2946 
2947 	tevent_req_done(req);
2948 }
2949 
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req * req)2950 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2951 {
2952 	NTSTATUS status;
2953 
2954 	if (tevent_req_is_nterror(req, &status)) {
2955 		netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2956 		tevent_req_received(req);
2957 		return status;
2958 	}
2959 
2960 	tevent_req_received(req);
2961 	return NT_STATUS_OK;
2962 }
2963 
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b,const char * site_name,uint32_t dns_ttl,struct NL_DNS_NAME_INFO_ARRAY * dns_names)2964 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2965 				struct netlogon_creds_cli_context *context,
2966 				struct dcerpc_binding_handle *b,
2967 				const char *site_name,
2968 				uint32_t dns_ttl,
2969 				struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2970 {
2971 	TALLOC_CTX *frame = talloc_stackframe();
2972 	struct tevent_context *ev;
2973 	struct tevent_req *req;
2974 	NTSTATUS status = NT_STATUS_NO_MEMORY;
2975 
2976 	ev = samba_tevent_context_init(frame);
2977 	if (ev == NULL) {
2978 		goto fail;
2979 	}
2980 	req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2981 									site_name,
2982 									dns_ttl,
2983 									dns_names);
2984 	if (req == NULL) {
2985 		goto fail;
2986 	}
2987 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2988 		goto fail;
2989 	}
2990 	status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2991  fail:
2992 	TALLOC_FREE(frame);
2993 	return status;
2994 }
2995 
2996 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2997 	struct tevent_context *ev;
2998 	struct netlogon_creds_cli_context *context;
2999 	struct dcerpc_binding_handle *binding_handle;
3000 
3001 	char *srv_name_slash;
3002 	enum dcerpc_AuthType auth_type;
3003 	enum dcerpc_AuthLevel auth_level;
3004 
3005 	struct samr_Password new_owf_password;
3006 	struct samr_Password old_owf_password;
3007 	struct netr_TrustInfo *trust_info;
3008 
3009 	struct netlogon_creds_CredentialState *creds;
3010 	struct netlogon_creds_CredentialState tmp_creds;
3011 	struct netr_Authenticator req_auth;
3012 	struct netr_Authenticator rep_auth;
3013 };
3014 
3015 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3016 						     NTSTATUS status);
3017 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
3018 
netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b)3019 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
3020 					struct tevent_context *ev,
3021 					struct netlogon_creds_cli_context *context,
3022 					struct dcerpc_binding_handle *b)
3023 {
3024 	struct tevent_req *req;
3025 	struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
3026 	struct tevent_req *subreq;
3027 
3028 	req = tevent_req_create(mem_ctx, &state,
3029 				struct netlogon_creds_cli_ServerGetTrustInfo_state);
3030 	if (req == NULL) {
3031 		return NULL;
3032 	}
3033 
3034 	state->ev = ev;
3035 	state->context = context;
3036 	state->binding_handle = b;
3037 
3038 	state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3039 						context->server.computer);
3040 	if (tevent_req_nomem(state->srv_name_slash, req)) {
3041 		return tevent_req_post(req, ev);
3042 	}
3043 
3044 	dcerpc_binding_handle_auth_info(state->binding_handle,
3045 					&state->auth_type,
3046 					&state->auth_level);
3047 
3048 	subreq = netlogon_creds_cli_lock_send(state, state->ev,
3049 					      state->context);
3050 	if (tevent_req_nomem(subreq, req)) {
3051 		return tevent_req_post(req, ev);
3052 	}
3053 
3054 	tevent_req_set_callback(subreq,
3055 				netlogon_creds_cli_ServerGetTrustInfo_locked,
3056 				req);
3057 
3058 	return req;
3059 }
3060 
netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req * req,NTSTATUS status)3061 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3062 							 NTSTATUS status)
3063 {
3064 	struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3065 		tevent_req_data(req,
3066 		struct netlogon_creds_cli_ServerGetTrustInfo_state);
3067 
3068 	if (state->creds == NULL) {
3069 		return;
3070 	}
3071 
3072 	if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3073 	    !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3074 	    !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3075 	    !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3076 	    !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3077 		TALLOC_FREE(state->creds);
3078 		return;
3079 	}
3080 
3081 	netlogon_creds_cli_delete(state->context, state->creds);
3082 	TALLOC_FREE(state->creds);
3083 }
3084 
3085 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3086 
netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req * subreq)3087 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3088 {
3089 	struct tevent_req *req =
3090 		tevent_req_callback_data(subreq,
3091 		struct tevent_req);
3092 	struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3093 		tevent_req_data(req,
3094 		struct netlogon_creds_cli_ServerGetTrustInfo_state);
3095 	NTSTATUS status;
3096 
3097 	status = netlogon_creds_cli_lock_recv(subreq, state,
3098 					      &state->creds);
3099 	TALLOC_FREE(subreq);
3100 	if (tevent_req_nterror(req, status)) {
3101 		return;
3102 	}
3103 
3104 	if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3105 		switch (state->auth_level) {
3106 		case DCERPC_AUTH_LEVEL_PRIVACY:
3107 			break;
3108 		default:
3109 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3110 			return;
3111 		}
3112 	} else {
3113 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3114 		return;
3115 	}
3116 
3117 	/*
3118 	 * we defer all callbacks in order to cleanup
3119 	 * the database record.
3120 	 */
3121 	tevent_req_defer_callback(req, state->ev);
3122 
3123 	state->tmp_creds = *state->creds;
3124 	status = netlogon_creds_client_authenticator(&state->tmp_creds,
3125 						     &state->req_auth);
3126 	if (tevent_req_nterror(req, status)) {
3127 		return;
3128 	}
3129 	ZERO_STRUCT(state->rep_auth);
3130 
3131 	subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3132 						     state->binding_handle,
3133 						     state->srv_name_slash,
3134 						     state->tmp_creds.account_name,
3135 						     state->tmp_creds.secure_channel_type,
3136 						     state->tmp_creds.computer_name,
3137 						     &state->req_auth,
3138 						     &state->rep_auth,
3139 						     &state->new_owf_password,
3140 						     &state->old_owf_password,
3141 						     &state->trust_info);
3142 	if (tevent_req_nomem(subreq, req)) {
3143 		status = NT_STATUS_NO_MEMORY;
3144 		netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3145 		return;
3146 	}
3147 
3148 	tevent_req_set_callback(subreq,
3149 				netlogon_creds_cli_ServerGetTrustInfo_done,
3150 				req);
3151 }
3152 
netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req * subreq)3153 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3154 {
3155 	struct tevent_req *req =
3156 		tevent_req_callback_data(subreq,
3157 		struct tevent_req);
3158 	struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3159 		tevent_req_data(req,
3160 		struct netlogon_creds_cli_ServerGetTrustInfo_state);
3161 	NTSTATUS status;
3162 	NTSTATUS result;
3163 	const struct samr_Password zero = {};
3164 	int cmp;
3165 	bool ok;
3166 
3167 	/*
3168 	 * We use state->dns_names as the memory context, as this is
3169 	 * the only in/out variable and it has been overwritten by the
3170 	 * out parameter from the server.
3171 	 *
3172 	 * We need to preserve the return value until the caller can use it.
3173 	 */
3174 	status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3175 	TALLOC_FREE(subreq);
3176 	if (tevent_req_nterror(req, status)) {
3177 		netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3178 		return;
3179 	}
3180 
3181 	ok = netlogon_creds_client_check(&state->tmp_creds,
3182 					 &state->rep_auth.cred);
3183 	if (!ok) {
3184 		status = NT_STATUS_ACCESS_DENIED;
3185 		tevent_req_nterror(req, status);
3186 		netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3187 		return;
3188 	}
3189 
3190 	cmp = memcmp(state->new_owf_password.hash,
3191 		     zero.hash, sizeof(zero.hash));
3192 	if (cmp != 0) {
3193 		status = netlogon_creds_des_decrypt(&state->tmp_creds,
3194 						    &state->new_owf_password);
3195 		if (tevent_req_nterror(req, status)) {
3196 			netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3197 			return;
3198 		}
3199 	}
3200 	cmp = memcmp(state->old_owf_password.hash,
3201 		     zero.hash, sizeof(zero.hash));
3202 	if (cmp != 0) {
3203 		status = netlogon_creds_des_decrypt(&state->tmp_creds,
3204 						    &state->old_owf_password);
3205 		if (tevent_req_nterror(req, status)) {
3206 			netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3207 			return;
3208 		}
3209 	}
3210 
3211 	*state->creds = state->tmp_creds;
3212 	status = netlogon_creds_cli_store(state->context,
3213 					  state->creds);
3214 	TALLOC_FREE(state->creds);
3215 	if (tevent_req_nterror(req, status)) {
3216 		netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3217 		return;
3218 	}
3219 
3220 	if (tevent_req_nterror(req, result)) {
3221 		netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3222 		return;
3223 	}
3224 
3225 	tevent_req_done(req);
3226 }
3227 
netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,struct samr_Password * new_owf_password,struct samr_Password * old_owf_password,struct netr_TrustInfo ** trust_info)3228 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3229 					TALLOC_CTX *mem_ctx,
3230 					struct samr_Password *new_owf_password,
3231 					struct samr_Password *old_owf_password,
3232 					struct netr_TrustInfo **trust_info)
3233 {
3234 	struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3235 		tevent_req_data(req,
3236 		struct netlogon_creds_cli_ServerGetTrustInfo_state);
3237 	NTSTATUS status;
3238 
3239 	if (tevent_req_is_nterror(req, &status)) {
3240 		netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3241 		tevent_req_received(req);
3242 		return status;
3243 	}
3244 
3245 	if (new_owf_password != NULL) {
3246 		*new_owf_password = state->new_owf_password;
3247 	}
3248 	if (old_owf_password != NULL) {
3249 		*old_owf_password = state->old_owf_password;
3250 	}
3251 	if (trust_info != NULL) {
3252 		*trust_info = talloc_move(mem_ctx, &state->trust_info);
3253 	}
3254 
3255 	tevent_req_received(req);
3256 	return NT_STATUS_OK;
3257 }
3258 
netlogon_creds_cli_ServerGetTrustInfo(struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b,TALLOC_CTX * mem_ctx,struct samr_Password * new_owf_password,struct samr_Password * old_owf_password,struct netr_TrustInfo ** trust_info)3259 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3260 				struct netlogon_creds_cli_context *context,
3261 				struct dcerpc_binding_handle *b,
3262 				TALLOC_CTX *mem_ctx,
3263 				struct samr_Password *new_owf_password,
3264 				struct samr_Password *old_owf_password,
3265 				struct netr_TrustInfo **trust_info)
3266 {
3267 	TALLOC_CTX *frame = talloc_stackframe();
3268 	struct tevent_context *ev;
3269 	struct tevent_req *req;
3270 	NTSTATUS status = NT_STATUS_NO_MEMORY;
3271 
3272 	ev = samba_tevent_context_init(frame);
3273 	if (ev == NULL) {
3274 		goto fail;
3275 	}
3276 	req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3277 	if (req == NULL) {
3278 		goto fail;
3279 	}
3280 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3281 		goto fail;
3282 	}
3283 	status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3284 							    mem_ctx,
3285 							    new_owf_password,
3286 							    old_owf_password,
3287 							    trust_info);
3288  fail:
3289 	TALLOC_FREE(frame);
3290 	return status;
3291 }
3292 
3293 struct netlogon_creds_cli_GetForestTrustInformation_state {
3294 	struct tevent_context *ev;
3295 	struct netlogon_creds_cli_context *context;
3296 	struct dcerpc_binding_handle *binding_handle;
3297 
3298 	char *srv_name_slash;
3299 	enum dcerpc_AuthType auth_type;
3300 	enum dcerpc_AuthLevel auth_level;
3301 
3302 	uint32_t flags;
3303 	struct lsa_ForestTrustInformation *forest_trust_info;
3304 
3305 	struct netlogon_creds_CredentialState *creds;
3306 	struct netlogon_creds_CredentialState tmp_creds;
3307 	struct netr_Authenticator req_auth;
3308 	struct netr_Authenticator rep_auth;
3309 };
3310 
3311 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3312 						     NTSTATUS status);
3313 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3314 
netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b)3315 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3316 					struct tevent_context *ev,
3317 					struct netlogon_creds_cli_context *context,
3318 					struct dcerpc_binding_handle *b)
3319 {
3320 	struct tevent_req *req;
3321 	struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3322 	struct tevent_req *subreq;
3323 
3324 	req = tevent_req_create(mem_ctx, &state,
3325 				struct netlogon_creds_cli_GetForestTrustInformation_state);
3326 	if (req == NULL) {
3327 		return NULL;
3328 	}
3329 
3330 	state->ev = ev;
3331 	state->context = context;
3332 	state->binding_handle = b;
3333 
3334 	state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3335 						context->server.computer);
3336 	if (tevent_req_nomem(state->srv_name_slash, req)) {
3337 		return tevent_req_post(req, ev);
3338 	}
3339 
3340 	state->flags = 0;
3341 
3342 	dcerpc_binding_handle_auth_info(state->binding_handle,
3343 					&state->auth_type,
3344 					&state->auth_level);
3345 
3346 	subreq = netlogon_creds_cli_lock_send(state, state->ev,
3347 					      state->context);
3348 	if (tevent_req_nomem(subreq, req)) {
3349 		return tevent_req_post(req, ev);
3350 	}
3351 
3352 	tevent_req_set_callback(subreq,
3353 				netlogon_creds_cli_GetForestTrustInformation_locked,
3354 				req);
3355 
3356 	return req;
3357 }
3358 
netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req * req,NTSTATUS status)3359 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3360 							 NTSTATUS status)
3361 {
3362 	struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3363 		tevent_req_data(req,
3364 		struct netlogon_creds_cli_GetForestTrustInformation_state);
3365 
3366 	if (state->creds == NULL) {
3367 		return;
3368 	}
3369 
3370 	if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3371 	    !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3372 	    !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3373 	    !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3374 	    !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3375 		TALLOC_FREE(state->creds);
3376 		return;
3377 	}
3378 
3379 	netlogon_creds_cli_delete(state->context, state->creds);
3380 	TALLOC_FREE(state->creds);
3381 }
3382 
3383 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3384 
netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req * subreq)3385 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3386 {
3387 	struct tevent_req *req =
3388 		tevent_req_callback_data(subreq,
3389 		struct tevent_req);
3390 	struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3391 		tevent_req_data(req,
3392 		struct netlogon_creds_cli_GetForestTrustInformation_state);
3393 	NTSTATUS status;
3394 
3395 	status = netlogon_creds_cli_lock_recv(subreq, state,
3396 					      &state->creds);
3397 	TALLOC_FREE(subreq);
3398 	if (tevent_req_nterror(req, status)) {
3399 		return;
3400 	}
3401 
3402 	if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3403 		switch (state->auth_level) {
3404 		case DCERPC_AUTH_LEVEL_INTEGRITY:
3405 		case DCERPC_AUTH_LEVEL_PRIVACY:
3406 			break;
3407 		default:
3408 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3409 			return;
3410 		}
3411 	} else {
3412 		uint32_t tmp = state->creds->negotiate_flags;
3413 
3414 		if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3415 			/*
3416 			 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3417 			 * it should be used, which means
3418 			 * we had a chance to verify no downgrade
3419 			 * happened.
3420 			 *
3421 			 * This relies on netlogon_creds_cli_check*
3422 			 * being called before, as first request after
3423 			 * the DCERPC bind.
3424 			 */
3425 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3426 			return;
3427 		}
3428 	}
3429 
3430 	/*
3431 	 * we defer all callbacks in order to cleanup
3432 	 * the database record.
3433 	 */
3434 	tevent_req_defer_callback(req, state->ev);
3435 
3436 	state->tmp_creds = *state->creds;
3437 	status = netlogon_creds_client_authenticator(&state->tmp_creds,
3438 						     &state->req_auth);
3439 	if (tevent_req_nterror(req, status)) {
3440 		return;
3441 	}
3442 	ZERO_STRUCT(state->rep_auth);
3443 
3444 	subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3445 						state->binding_handle,
3446 						state->srv_name_slash,
3447 						state->tmp_creds.computer_name,
3448 						&state->req_auth,
3449 						&state->rep_auth,
3450 						state->flags,
3451 						&state->forest_trust_info);
3452 	if (tevent_req_nomem(subreq, req)) {
3453 		status = NT_STATUS_NO_MEMORY;
3454 		netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3455 		return;
3456 	}
3457 
3458 	tevent_req_set_callback(subreq,
3459 				netlogon_creds_cli_GetForestTrustInformation_done,
3460 				req);
3461 }
3462 
netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req * subreq)3463 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3464 {
3465 	struct tevent_req *req =
3466 		tevent_req_callback_data(subreq,
3467 		struct tevent_req);
3468 	struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3469 		tevent_req_data(req,
3470 		struct netlogon_creds_cli_GetForestTrustInformation_state);
3471 	NTSTATUS status;
3472 	NTSTATUS result;
3473 	bool ok;
3474 
3475 	/*
3476 	 * We use state->dns_names as the memory context, as this is
3477 	 * the only in/out variable and it has been overwritten by the
3478 	 * out parameter from the server.
3479 	 *
3480 	 * We need to preserve the return value until the caller can use it.
3481 	 */
3482 	status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3483 	TALLOC_FREE(subreq);
3484 	if (tevent_req_nterror(req, status)) {
3485 		netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3486 		return;
3487 	}
3488 
3489 	ok = netlogon_creds_client_check(&state->tmp_creds,
3490 					 &state->rep_auth.cred);
3491 	if (!ok) {
3492 		status = NT_STATUS_ACCESS_DENIED;
3493 		tevent_req_nterror(req, status);
3494 		netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3495 		return;
3496 	}
3497 
3498 	*state->creds = state->tmp_creds;
3499 	status = netlogon_creds_cli_store(state->context,
3500 					  state->creds);
3501 	TALLOC_FREE(state->creds);
3502 
3503 	if (tevent_req_nterror(req, status)) {
3504 		netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3505 		return;
3506 	}
3507 
3508 	if (tevent_req_nterror(req, result)) {
3509 		netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3510 		return;
3511 	}
3512 
3513 	tevent_req_done(req);
3514 }
3515 
netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,struct lsa_ForestTrustInformation ** forest_trust_info)3516 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3517 			TALLOC_CTX *mem_ctx,
3518 			struct lsa_ForestTrustInformation **forest_trust_info)
3519 {
3520 	struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3521 		tevent_req_data(req,
3522 		struct netlogon_creds_cli_GetForestTrustInformation_state);
3523 	NTSTATUS status;
3524 
3525 	if (tevent_req_is_nterror(req, &status)) {
3526 		netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3527 		tevent_req_received(req);
3528 		return status;
3529 	}
3530 
3531 	*forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3532 
3533 	tevent_req_received(req);
3534 	return NT_STATUS_OK;
3535 }
3536 
netlogon_creds_cli_GetForestTrustInformation(struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b,TALLOC_CTX * mem_ctx,struct lsa_ForestTrustInformation ** forest_trust_info)3537 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3538 			struct netlogon_creds_cli_context *context,
3539 			struct dcerpc_binding_handle *b,
3540 			TALLOC_CTX *mem_ctx,
3541 			struct lsa_ForestTrustInformation **forest_trust_info)
3542 {
3543 	TALLOC_CTX *frame = talloc_stackframe();
3544 	struct tevent_context *ev;
3545 	struct tevent_req *req;
3546 	NTSTATUS status = NT_STATUS_NO_MEMORY;
3547 
3548 	ev = samba_tevent_context_init(frame);
3549 	if (ev == NULL) {
3550 		goto fail;
3551 	}
3552 	req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3553 	if (req == NULL) {
3554 		goto fail;
3555 	}
3556 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3557 		goto fail;
3558 	}
3559 	status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3560 							mem_ctx,
3561 							forest_trust_info);
3562  fail:
3563 	TALLOC_FREE(frame);
3564 	return status;
3565 }
3566 struct netlogon_creds_cli_SendToSam_state {
3567 	struct tevent_context *ev;
3568 	struct netlogon_creds_cli_context *context;
3569 	struct dcerpc_binding_handle *binding_handle;
3570 
3571 	char *srv_name_slash;
3572 	enum dcerpc_AuthType auth_type;
3573 	enum dcerpc_AuthLevel auth_level;
3574 
3575 	DATA_BLOB opaque;
3576 
3577 	struct netlogon_creds_CredentialState *creds;
3578 	struct netlogon_creds_CredentialState tmp_creds;
3579 	struct netr_Authenticator req_auth;
3580 	struct netr_Authenticator rep_auth;
3581 };
3582 
3583 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3584 								 NTSTATUS status);
3585 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3586 
netlogon_creds_cli_SendToSam_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b,struct netr_SendToSamBase * message)3587 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3588 						     struct tevent_context *ev,
3589 						     struct netlogon_creds_cli_context *context,
3590 						     struct dcerpc_binding_handle *b,
3591 						     struct netr_SendToSamBase *message)
3592 {
3593 	struct tevent_req *req;
3594 	struct netlogon_creds_cli_SendToSam_state *state;
3595 	struct tevent_req *subreq;
3596 	enum ndr_err_code ndr_err;
3597 
3598 	req = tevent_req_create(mem_ctx, &state,
3599 				struct netlogon_creds_cli_SendToSam_state);
3600 	if (req == NULL) {
3601 		return NULL;
3602 	}
3603 
3604 	state->ev = ev;
3605 	state->context = context;
3606 	state->binding_handle = b;
3607 
3608 	state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3609 						context->server.computer);
3610 	if (tevent_req_nomem(state->srv_name_slash, req)) {
3611 		return tevent_req_post(req, ev);
3612 	}
3613 
3614 	ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3615 				       (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3616 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3617 		NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3618 		tevent_req_nterror(req, status);
3619 		return tevent_req_post(req, ev);
3620 	}
3621 
3622 	dcerpc_binding_handle_auth_info(state->binding_handle,
3623 					&state->auth_type,
3624 					&state->auth_level);
3625 
3626 	subreq = netlogon_creds_cli_lock_send(state, state->ev,
3627 					      state->context);
3628 	if (tevent_req_nomem(subreq, req)) {
3629 		return tevent_req_post(req, ev);
3630 	}
3631 
3632 	tevent_req_set_callback(subreq,
3633 				netlogon_creds_cli_SendToSam_locked,
3634 				req);
3635 
3636 	return req;
3637 }
3638 
netlogon_creds_cli_SendToSam_cleanup(struct tevent_req * req,NTSTATUS status)3639 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3640 							 NTSTATUS status)
3641 {
3642 	struct netlogon_creds_cli_SendToSam_state *state =
3643 		tevent_req_data(req,
3644 		struct netlogon_creds_cli_SendToSam_state);
3645 
3646 	if (state->creds == NULL) {
3647 		return;
3648 	}
3649 
3650 	if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3651 	    !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3652 	    !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3653 	    !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3654 	    !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3655 		TALLOC_FREE(state->creds);
3656 		return;
3657 	}
3658 
3659 	netlogon_creds_cli_delete(state->context, state->creds);
3660 	TALLOC_FREE(state->creds);
3661 }
3662 
3663 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3664 
netlogon_creds_cli_SendToSam_locked(struct tevent_req * subreq)3665 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3666 {
3667 	struct tevent_req *req =
3668 		tevent_req_callback_data(subreq,
3669 		struct tevent_req);
3670 	struct netlogon_creds_cli_SendToSam_state *state =
3671 		tevent_req_data(req,
3672 		struct netlogon_creds_cli_SendToSam_state);
3673 	NTSTATUS status;
3674 
3675 	status = netlogon_creds_cli_lock_recv(subreq, state,
3676 					      &state->creds);
3677 	TALLOC_FREE(subreq);
3678 	if (tevent_req_nterror(req, status)) {
3679 		return;
3680 	}
3681 
3682 	if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3683 		switch (state->auth_level) {
3684 		case DCERPC_AUTH_LEVEL_INTEGRITY:
3685 		case DCERPC_AUTH_LEVEL_PRIVACY:
3686 			break;
3687 		default:
3688 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3689 			return;
3690 		}
3691 	} else {
3692 		uint32_t tmp = state->creds->negotiate_flags;
3693 
3694 		if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3695 			/*
3696 			 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3697 			 * it should be used, which means
3698 			 * we had a chance to verify no downgrade
3699 			 * happened.
3700 			 *
3701 			 * This relies on netlogon_creds_cli_check*
3702 			 * being called before, as first request after
3703 			 * the DCERPC bind.
3704 			 */
3705 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3706 			return;
3707 		}
3708 	}
3709 
3710 	/*
3711 	 * we defer all callbacks in order to cleanup
3712 	 * the database record.
3713 	 */
3714 	tevent_req_defer_callback(req, state->ev);
3715 
3716 	state->tmp_creds = *state->creds;
3717 	status = netlogon_creds_client_authenticator(&state->tmp_creds,
3718 						     &state->req_auth);
3719 	if (tevent_req_nterror(req, status)) {
3720 		return;
3721 	}
3722 	ZERO_STRUCT(state->rep_auth);
3723 
3724 	if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3725 		status = netlogon_creds_aes_encrypt(&state->tmp_creds,
3726 						    state->opaque.data,
3727 						    state->opaque.length);
3728 		if (tevent_req_nterror(req, status)) {
3729 			netlogon_creds_cli_SendToSam_cleanup(req, status);
3730 			return;
3731 		}
3732 	} else {
3733 		status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
3734 						      state->opaque.data,
3735 						      state->opaque.length);
3736 		if (tevent_req_nterror(req, status)) {
3737 			netlogon_creds_cli_SendToSam_cleanup(req, status);
3738 			return;
3739 		}
3740 	}
3741 
3742 	subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3743 						     state->binding_handle,
3744 						     state->srv_name_slash,
3745 						     state->tmp_creds.computer_name,
3746 						     &state->req_auth,
3747 						     &state->rep_auth,
3748 						     state->opaque.data,
3749 						     state->opaque.length);
3750 	if (tevent_req_nomem(subreq, req)) {
3751 		status = NT_STATUS_NO_MEMORY;
3752 		netlogon_creds_cli_SendToSam_cleanup(req, status);
3753 		return;
3754 	}
3755 
3756 	tevent_req_set_callback(subreq,
3757 				netlogon_creds_cli_SendToSam_done,
3758 				req);
3759 }
3760 
netlogon_creds_cli_SendToSam_done(struct tevent_req * subreq)3761 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3762 {
3763 	struct tevent_req *req =
3764 		tevent_req_callback_data(subreq,
3765 		struct tevent_req);
3766 	struct netlogon_creds_cli_SendToSam_state *state =
3767 		tevent_req_data(req,
3768 		struct netlogon_creds_cli_SendToSam_state);
3769 	NTSTATUS status;
3770 	NTSTATUS result;
3771 	bool ok;
3772 
3773 	status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3774 	TALLOC_FREE(subreq);
3775 	if (tevent_req_nterror(req, status)) {
3776 		netlogon_creds_cli_SendToSam_cleanup(req, status);
3777 		return;
3778 	}
3779 
3780 	ok = netlogon_creds_client_check(&state->tmp_creds,
3781 					 &state->rep_auth.cred);
3782 	if (!ok) {
3783 		status = NT_STATUS_ACCESS_DENIED;
3784 		tevent_req_nterror(req, status);
3785 		netlogon_creds_cli_SendToSam_cleanup(req, status);
3786 		return;
3787 	}
3788 
3789 	*state->creds = state->tmp_creds;
3790 	status = netlogon_creds_cli_store(state->context,
3791 					  state->creds);
3792 	TALLOC_FREE(state->creds);
3793 
3794 	if (tevent_req_nterror(req, status)) {
3795 		netlogon_creds_cli_SendToSam_cleanup(req, status);
3796 		return;
3797 	}
3798 
3799 	/*
3800 	 * Creds must be stored before we send back application errors
3801 	 * e.g. NT_STATUS_NOT_IMPLEMENTED
3802 	 */
3803 	if (tevent_req_nterror(req, result)) {
3804 		netlogon_creds_cli_SendToSam_cleanup(req, result);
3805 		return;
3806 	}
3807 
3808 	tevent_req_done(req);
3809 }
3810 
netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b,struct netr_SendToSamBase * message)3811 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3812 				      struct dcerpc_binding_handle *b,
3813 				      struct netr_SendToSamBase *message)
3814 {
3815 	TALLOC_CTX *frame = talloc_stackframe();
3816 	struct tevent_context *ev;
3817 	struct tevent_req *req;
3818 	NTSTATUS status = NT_STATUS_OK;
3819 
3820 	ev = samba_tevent_context_init(frame);
3821 	if (ev == NULL) {
3822 		goto fail;
3823 	}
3824 	req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3825 	if (req == NULL) {
3826 		goto fail;
3827 	}
3828 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3829 		goto fail;
3830 	}
3831 
3832 	/* Ignore the result */
3833  fail:
3834 	TALLOC_FREE(frame);
3835 	return status;
3836 }
3837 
3838 struct netlogon_creds_cli_LogonGetDomainInfo_state {
3839 	struct tevent_context *ev;
3840 	struct netlogon_creds_cli_context *context;
3841 	struct dcerpc_binding_handle *binding_handle;
3842 
3843 	char *srv_name_slash;
3844 	enum dcerpc_AuthType auth_type;
3845 	enum dcerpc_AuthLevel auth_level;
3846 
3847 	uint32_t level;
3848 	union netr_WorkstationInfo *query;
3849 	union netr_DomainInfo *info;
3850 
3851 	struct netlogon_creds_CredentialState *creds;
3852 	struct netlogon_creds_CredentialState tmp_creds;
3853 	struct netr_Authenticator req_auth;
3854 	struct netr_Authenticator rep_auth;
3855 };
3856 
3857 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
3858 						     NTSTATUS status);
3859 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq);
3860 
netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b,uint32_t level,union netr_WorkstationInfo * query)3861 struct tevent_req *netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX *mem_ctx,
3862 					struct tevent_context *ev,
3863 					struct netlogon_creds_cli_context *context,
3864 					struct dcerpc_binding_handle *b,
3865 					uint32_t level,
3866 					union netr_WorkstationInfo *query)
3867 {
3868 	struct tevent_req *req;
3869 	struct netlogon_creds_cli_LogonGetDomainInfo_state *state;
3870 	struct tevent_req *subreq;
3871 
3872 	req = tevent_req_create(mem_ctx, &state,
3873 				struct netlogon_creds_cli_LogonGetDomainInfo_state);
3874 	if (req == NULL) {
3875 		return NULL;
3876 	}
3877 
3878 	state->ev = ev;
3879 	state->context = context;
3880 	state->binding_handle = b;
3881 
3882 	state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3883 						context->server.computer);
3884 	if (tevent_req_nomem(state->srv_name_slash, req)) {
3885 		return tevent_req_post(req, ev);
3886 	}
3887 
3888 	state->level = level;
3889 	state->query = query;
3890 	state->info = talloc_zero(state, union netr_DomainInfo);
3891 	if (tevent_req_nomem(state->info, req)) {
3892 		return tevent_req_post(req, ev);
3893 	}
3894 
3895 	dcerpc_binding_handle_auth_info(state->binding_handle,
3896 					&state->auth_type,
3897 					&state->auth_level);
3898 
3899 	subreq = netlogon_creds_cli_lock_send(state, state->ev,
3900 					      state->context);
3901 	if (tevent_req_nomem(subreq, req)) {
3902 		return tevent_req_post(req, ev);
3903 	}
3904 
3905 	tevent_req_set_callback(subreq,
3906 				netlogon_creds_cli_LogonGetDomainInfo_locked,
3907 				req);
3908 
3909 	return req;
3910 }
3911 
netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req * req,NTSTATUS status)3912 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
3913 							 NTSTATUS status)
3914 {
3915 	struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
3916 		tevent_req_data(req,
3917 		struct netlogon_creds_cli_LogonGetDomainInfo_state);
3918 
3919 	if (state->creds == NULL) {
3920 		return;
3921 	}
3922 
3923 	if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3924 	    !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3925 	    !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3926 	    !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3927 	    !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3928 		TALLOC_FREE(state->creds);
3929 		return;
3930 	}
3931 
3932 	netlogon_creds_cli_delete(state->context, state->creds);
3933 }
3934 
3935 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq);
3936 
netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req * subreq)3937 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq)
3938 {
3939 	struct tevent_req *req =
3940 		tevent_req_callback_data(subreq,
3941 		struct tevent_req);
3942 	struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
3943 		tevent_req_data(req,
3944 		struct netlogon_creds_cli_LogonGetDomainInfo_state);
3945 	NTSTATUS status;
3946 
3947 	status = netlogon_creds_cli_lock_recv(subreq, state,
3948 					      &state->creds);
3949 	TALLOC_FREE(subreq);
3950 	if (tevent_req_nterror(req, status)) {
3951 		return;
3952 	}
3953 
3954 	if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3955 		switch (state->auth_level) {
3956 		case DCERPC_AUTH_LEVEL_INTEGRITY:
3957 		case DCERPC_AUTH_LEVEL_PRIVACY:
3958 			break;
3959 		default:
3960 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3961 			return;
3962 		}
3963 	} else {
3964 		uint32_t tmp = state->creds->negotiate_flags;
3965 
3966 		if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3967 			/*
3968 			 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3969 			 * it should be used, which means
3970 			 * we had a chance to verify no downgrade
3971 			 * happened.
3972 			 *
3973 			 * This relies on netlogon_creds_cli_check*
3974 			 * being called before, as first request after
3975 			 * the DCERPC bind.
3976 			 */
3977 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3978 			return;
3979 		}
3980 	}
3981 
3982 	/*
3983 	 * we defer all callbacks in order to cleanup
3984 	 * the database record.
3985 	 */
3986 	tevent_req_defer_callback(req, state->ev);
3987 
3988 	state->tmp_creds = *state->creds;
3989 	status = netlogon_creds_client_authenticator(&state->tmp_creds,
3990 						     &state->req_auth);
3991 	if (tevent_req_nterror(req, status)) {
3992 		return;
3993 	}
3994 	ZERO_STRUCT(state->rep_auth);
3995 
3996 	subreq = dcerpc_netr_LogonGetDomainInfo_send(state, state->ev,
3997 						state->binding_handle,
3998 						state->srv_name_slash,
3999 						state->tmp_creds.computer_name,
4000 						&state->req_auth,
4001 						&state->rep_auth,
4002 						state->level,
4003 						state->query,
4004 						state->info);
4005 	if (tevent_req_nomem(subreq, req)) {
4006 		status = NT_STATUS_NO_MEMORY;
4007 		netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4008 		return;
4009 	}
4010 
4011 	tevent_req_set_callback(subreq,
4012 				netlogon_creds_cli_LogonGetDomainInfo_done,
4013 				req);
4014 }
4015 
netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req * subreq)4016 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq)
4017 {
4018 	struct tevent_req *req =
4019 		tevent_req_callback_data(subreq,
4020 		struct tevent_req);
4021 	struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4022 		tevent_req_data(req,
4023 		struct netlogon_creds_cli_LogonGetDomainInfo_state);
4024 	NTSTATUS status;
4025 	NTSTATUS result;
4026 	bool ok;
4027 
4028 	/*
4029 	 * We use state->dns_names as the memory context, as this is
4030 	 * the only in/out variable and it has been overwritten by the
4031 	 * out parameter from the server.
4032 	 *
4033 	 * We need to preserve the return value until the caller can use it.
4034 	 */
4035 	status = dcerpc_netr_LogonGetDomainInfo_recv(subreq, state->info, &result);
4036 	TALLOC_FREE(subreq);
4037 	if (tevent_req_nterror(req, status)) {
4038 		netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4039 		return;
4040 	}
4041 
4042 	ok = netlogon_creds_client_check(&state->tmp_creds,
4043 					 &state->rep_auth.cred);
4044 	if (!ok) {
4045 		status = NT_STATUS_ACCESS_DENIED;
4046 		tevent_req_nterror(req, status);
4047 		netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4048 		return;
4049 	}
4050 
4051 	if (tevent_req_nterror(req, result)) {
4052 		netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, result);
4053 		return;
4054 	}
4055 
4056 	*state->creds = state->tmp_creds;
4057 	status = netlogon_creds_cli_store(state->context,
4058 					  state->creds);
4059 	if (tevent_req_nterror(req, status)) {
4060 		netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4061 		return;
4062 	}
4063 
4064 	tevent_req_done(req);
4065 }
4066 
netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,union netr_DomainInfo ** info)4067 NTSTATUS netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req *req,
4068 			TALLOC_CTX *mem_ctx,
4069 			union netr_DomainInfo **info)
4070 {
4071 	struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4072 		tevent_req_data(req,
4073 		struct netlogon_creds_cli_LogonGetDomainInfo_state);
4074 	NTSTATUS status;
4075 
4076 	if (tevent_req_is_nterror(req, &status)) {
4077 		netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4078 		tevent_req_received(req);
4079 		return status;
4080 	}
4081 
4082 	*info = talloc_move(mem_ctx, &state->info);
4083 
4084 	tevent_req_received(req);
4085 	return NT_STATUS_OK;
4086 }
4087 
netlogon_creds_cli_LogonGetDomainInfo(struct netlogon_creds_cli_context * context,struct dcerpc_binding_handle * b,TALLOC_CTX * mem_ctx,uint32_t level,union netr_WorkstationInfo * query,union netr_DomainInfo ** info)4088 NTSTATUS netlogon_creds_cli_LogonGetDomainInfo(
4089 			struct netlogon_creds_cli_context *context,
4090 			struct dcerpc_binding_handle *b,
4091 			TALLOC_CTX *mem_ctx,
4092 			uint32_t level,
4093 			union netr_WorkstationInfo *query,
4094 			union netr_DomainInfo **info)
4095 {
4096 	TALLOC_CTX *frame = talloc_stackframe();
4097 	struct tevent_context *ev;
4098 	struct tevent_req *req;
4099 	NTSTATUS status = NT_STATUS_OK;
4100 
4101 	ev = samba_tevent_context_init(frame);
4102 	if (ev == NULL) {
4103 		goto fail;
4104 	}
4105 	req = netlogon_creds_cli_LogonGetDomainInfo_send(frame, ev, context, b,
4106 							 level, query);
4107 	if (req == NULL) {
4108 		goto fail;
4109 	}
4110 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4111 		goto fail;
4112 	}
4113 	status = netlogon_creds_cli_LogonGetDomainInfo_recv(req,
4114 							    mem_ctx,
4115 							    info);
4116  fail:
4117 	TALLOC_FREE(frame);
4118 	return status;
4119 }
4120