Exemple #1
0
NTSTATUS rpccli_connect_netlogon(
	struct cli_state *cli,
	enum dcerpc_transport_t transport,
	struct netlogon_creds_cli_context *creds_ctx,
	bool force_reauth,
	struct cli_credentials *trust_creds,
	struct rpc_pipe_client **_rpccli)
{
	TALLOC_CTX *frame = talloc_stackframe();
	struct netlogon_creds_CredentialState *creds = NULL;
	enum netlogon_creds_cli_lck_type lck_type;
	enum netr_SchannelType sec_chan_type;
	struct netlogon_creds_cli_lck *lck = NULL;
	uint32_t negotiate_flags;
	uint8_t found_session_key[16] = {0};
	bool found_existing_creds = false;
	bool do_serverauth;
	struct rpc_pipe_client *rpccli;
	NTSTATUS status;
	bool retry = false;

	sec_chan_type = cli_credentials_get_secure_channel_type(trust_creds);
	if (sec_chan_type == SEC_CHAN_NULL) {
		DBG_ERR("secure_channel_type gave SEC_CHAN_NULL\n");
		status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
		goto fail;
	}

again:

	/*
	 * See whether we can use existing netlogon_creds or
	 * whether we have to serverauthenticate.
	 */
	status = netlogon_creds_cli_get(creds_ctx, frame, &creds);

	if (NT_STATUS_IS_OK(status)) {
		int cmp = memcmp(found_session_key,
				 creds->session_key,
				 sizeof(found_session_key));
		found_existing_creds = (cmp != 0);

		memcpy(found_session_key,
		       creds->session_key,
		       sizeof(found_session_key));

		TALLOC_FREE(creds);
	}

	lck_type = (force_reauth || !found_existing_creds) ?
		NETLOGON_CREDS_CLI_LCK_EXCLUSIVE :
		NETLOGON_CREDS_CLI_LCK_SHARED;

	status = netlogon_creds_cli_lck(creds_ctx, lck_type, frame, &lck);
	if (!NT_STATUS_IS_OK(status)) {
		DBG_DEBUG("netlogon_creds_cli_lck failed: %s\n",
			  nt_errstr(status));
		goto fail;
	}

	if (!found_existing_creds) {
		/*
		 * Try to find creds under the lock again. Someone
		 * else might have done it for us.
		 */
		status = netlogon_creds_cli_get(creds_ctx, frame, &creds);

		if (NT_STATUS_IS_OK(status)) {
			int cmp = memcmp(found_session_key,
					 creds->session_key,
					 sizeof(found_session_key));
			found_existing_creds = (cmp != 0);

			memcpy(found_session_key, creds->session_key,
			       sizeof(found_session_key));

			TALLOC_FREE(creds);
		}
	}

	do_serverauth = force_reauth || !found_existing_creds;

	if (!do_serverauth) {
		/*
		 * Do the quick schannel bind without a reauth
		 */
		status = cli_rpc_pipe_open_bind_schannel(
			cli, &ndr_table_netlogon, transport, creds_ctx,
			&rpccli);
		if (!retry && NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
			DBG_DEBUG("Retrying with serverauthenticate\n");
			TALLOC_FREE(lck);
			retry = true;
			goto again;
		}
		if (!NT_STATUS_IS_OK(status)) {
			DBG_DEBUG("cli_rpc_pipe_open_bind_schannel "
				  "failed: %s\n", nt_errstr(status));
			goto fail;
		}
		goto done;
	}

	if (cli_credentials_is_anonymous(trust_creds)) {
		DBG_WARNING("get_trust_credential for %s only gave anonymous,"
			    "unable to negotiate NETLOGON credentials\n",
			    netlogon_creds_cli_debug_string(
				    creds_ctx, frame));
		status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
		goto fail;
	}

	status = rpccli_setup_netlogon_creds_locked(
		cli, transport, creds_ctx, true, trust_creds,
		&negotiate_flags);
	if (!NT_STATUS_IS_OK(status)) {
		DBG_DEBUG("rpccli_setup_netlogon_creds failed for %s, "
			  "unable to setup NETLOGON credentials: %s\n",
			  netlogon_creds_cli_debug_string(
				  creds_ctx, frame),
			  nt_errstr(status));
		goto fail;
	}

	if (!(negotiate_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
		if (lp_winbind_sealed_pipes() || lp_require_strong_key()) {
			status = NT_STATUS_DOWNGRADE_DETECTED;
			DBG_WARNING("Unwilling to make connection to %s"
				    "without connection level security, "
				    "must set 'winbind sealed pipes = false'"
				    " and 'require strong key = false' "
				    "to proceed: %s\n",
				    netlogon_creds_cli_debug_string(
					    creds_ctx, frame),
				    nt_errstr(status));
			goto fail;
		}

		status = cli_rpc_pipe_open_noauth_transport(
			cli, transport, &ndr_table_netlogon, &rpccli);
		if (!NT_STATUS_IS_OK(status)) {
			DBG_DEBUG("cli_rpc_pipe_open_noauth_transport "
				  "failed: %s\n", nt_errstr(status));
			goto fail;
		}
		goto done;
	}

	status = cli_rpc_pipe_open_bind_schannel(
		cli, &ndr_table_netlogon, transport, creds_ctx, &rpccli);
	if (!NT_STATUS_IS_OK(status)) {
		DBG_DEBUG("cli_rpc_pipe_open_bind_schannel "
			  "failed: %s\n", nt_errstr(status));
		goto fail;
	}

	status = netlogon_creds_cli_check(creds_ctx, rpccli->binding_handle,
					  NULL);
	if (!NT_STATUS_IS_OK(status)) {
		DBG_WARNING("netlogon_creds_cli_check failed: %s\n",
			    nt_errstr(status));
		goto fail;
	}

done:
	*_rpccli = rpccli;
	status = NT_STATUS_OK;
fail:
	ZERO_STRUCT(found_session_key);
	TALLOC_FREE(lck);
	TALLOC_FREE(frame);
	return status;
}
Exemple #2
0
NTSTATUS rpccli_setup_netlogon_creds(struct cli_state *cli,
				     enum dcerpc_transport_t transport,
				     struct netlogon_creds_cli_context *netlogon_creds,
				     bool force_reauth,
				     struct samr_Password current_nt_hash,
				     const struct samr_Password *previous_nt_hash)
{
	TALLOC_CTX *frame = talloc_stackframe();
	struct rpc_pipe_client *netlogon_pipe = NULL;
	struct netlogon_creds_CredentialState *creds = NULL;
	NTSTATUS status;

	status = netlogon_creds_cli_get(netlogon_creds,
					frame, &creds);
	if (NT_STATUS_IS_OK(status)) {
		const char *action = "using";

		if (force_reauth) {
			action = "overwrite";
		}

		DEBUG(5,("%s: %s cached netlogon_creds cli[%s/%s] to %s\n",
			 __FUNCTION__, action,
			 creds->account_name, creds->computer_name,
			 smbXcli_conn_remote_name(cli->conn)));
		if (!force_reauth) {
			TALLOC_FREE(frame);
			return NT_STATUS_OK;
		}
		TALLOC_FREE(creds);
	}

	status = cli_rpc_pipe_open_noauth_transport(cli,
						    transport,
						    &ndr_table_netlogon,
						    &netlogon_pipe);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(5,("%s: failed to open noauth netlogon connection to %s - %s\n",
			 __FUNCTION__,
			 smbXcli_conn_remote_name(cli->conn),
			 nt_errstr(status)));
		TALLOC_FREE(frame);
		return status;
	}
	talloc_steal(frame, netlogon_pipe);

	status = netlogon_creds_cli_auth(netlogon_creds,
					 netlogon_pipe->binding_handle,
					 current_nt_hash,
					 previous_nt_hash);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(frame);
		return status;
	}

	status = netlogon_creds_cli_get(netlogon_creds,
					frame, &creds);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(frame);
		return NT_STATUS_INTERNAL_ERROR;
	}

	DEBUG(5,("%s: using new netlogon_creds cli[%s/%s] to %s\n",
		 __FUNCTION__,
		 creds->account_name, creds->computer_name,
		 smbXcli_conn_remote_name(cli->conn)));

	TALLOC_FREE(frame);
	return NT_STATUS_OK;
}
Exemple #3
0
NTSTATUS rpccli_setup_netlogon_creds_locked(
	struct cli_state *cli,
	enum dcerpc_transport_t transport,
	struct netlogon_creds_cli_context *creds_ctx,
	bool force_reauth,
	struct cli_credentials *cli_creds,
	uint32_t *negotiate_flags)
{
	TALLOC_CTX *frame = talloc_stackframe();
	struct rpc_pipe_client *netlogon_pipe = NULL;
	struct netlogon_creds_CredentialState *creds = NULL;
	uint8_t num_nt_hashes = 0;
	const struct samr_Password *nt_hashes[2] = { NULL, NULL };
	uint8_t idx_nt_hashes = 0;
	NTSTATUS status;

	status = netlogon_creds_cli_get(creds_ctx, frame, &creds);
	if (NT_STATUS_IS_OK(status)) {
		const char *action = "using";

		if (force_reauth) {
			action = "overwrite";
		}

		DEBUG(5,("%s: %s cached netlogon_creds cli[%s/%s] to %s\n",
			 __FUNCTION__, action,
			 creds->account_name, creds->computer_name,
			 smbXcli_conn_remote_name(cli->conn)));
		if (!force_reauth) {
			goto done;
		}
		TALLOC_FREE(creds);
	}

	nt_hashes[0] = cli_credentials_get_nt_hash(cli_creds, talloc_tos());
	if (nt_hashes[0] == NULL) {
		TALLOC_FREE(frame);
		return NT_STATUS_NO_MEMORY;
	}
	num_nt_hashes = 1;

	nt_hashes[1] = cli_credentials_get_old_nt_hash(cli_creds,
						       talloc_tos());
	if (nt_hashes[1] != NULL) {
		num_nt_hashes = 2;
	}

	status = cli_rpc_pipe_open_noauth_transport(cli,
						    transport,
						    &ndr_table_netlogon,
						    &netlogon_pipe);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(5,("%s: failed to open noauth netlogon connection to %s - %s\n",
			 __FUNCTION__,
			 smbXcli_conn_remote_name(cli->conn),
			 nt_errstr(status)));
		TALLOC_FREE(frame);
		return status;
	}
	talloc_steal(frame, netlogon_pipe);

	status = netlogon_creds_cli_auth(creds_ctx,
					 netlogon_pipe->binding_handle,
					 num_nt_hashes,
					 nt_hashes,
					 &idx_nt_hashes);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(frame);
		return status;
	}

	status = netlogon_creds_cli_get(creds_ctx, frame, &creds);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(frame);
		return NT_STATUS_INTERNAL_ERROR;
	}

	DEBUG(5,("%s: using new netlogon_creds cli[%s/%s] to %s\n",
		 __FUNCTION__,
		 creds->account_name, creds->computer_name,
		 smbXcli_conn_remote_name(cli->conn)));

done:
	if (negotiate_flags != NULL) {
		*negotiate_flags = creds->negotiate_flags;
	}

	TALLOC_FREE(frame);
	return NT_STATUS_OK;
}
static NTSTATUS connect_to_domain_password_server(struct cli_state **cli_ret,
						const char *domain,
						const char *dc_name,
						const struct sockaddr_storage *dc_ss,
						struct rpc_pipe_client **pipe_ret,
						TALLOC_CTX *mem_ctx,
						struct netlogon_creds_cli_context **creds_ret)
{
	TALLOC_CTX *frame = talloc_stackframe();
	struct messaging_context *msg_ctx = server_messaging_context();
	NTSTATUS result;
	struct cli_state *cli = NULL;
	struct rpc_pipe_client *netlogon_pipe = NULL;
	struct netlogon_creds_cli_context *netlogon_creds = NULL;
	struct netlogon_creds_CredentialState *creds = NULL;
	uint32_t netlogon_flags = 0;
	enum netr_SchannelType sec_chan_type = 0;
	const char *_account_name = NULL;
	const char *account_name = NULL;
	struct samr_Password current_nt_hash;
	struct samr_Password *previous_nt_hash = NULL;
	bool ok;

	*cli_ret = NULL;

	*pipe_ret = NULL;
	*creds_ret = NULL;

	/* TODO: Send a SAMLOGON request to determine whether this is a valid
	   logonserver.  We can avoid a 30-second timeout if the DC is down
	   if the SAMLOGON request fails as it is only over UDP. */

	/* we use a mutex to prevent two connections at once - when a 
	   Win2k PDC get two connections where one hasn't completed a 
	   session setup yet it will send a TCP reset to the first 
	   connection (tridge) */

	/*
	 * With NT4.x DC's *all* authentication must be serialized to avoid
	 * ACCESS_DENIED errors if 2 auths are done from the same machine. JRA.
	 */

	mutex = grab_named_mutex(NULL, dc_name, 10);
	if (mutex == NULL) {
		TALLOC_FREE(frame);
		return NT_STATUS_NO_LOGON_SERVERS;
	}

	/* Attempt connection */
	result = cli_full_connection(&cli, lp_netbios_name(), dc_name, dc_ss, 0,
		"IPC$", "IPC", "", "", "", 0, SMB_SIGNING_DEFAULT);

	if (!NT_STATUS_IS_OK(result)) {
		/* map to something more useful */
		if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
			result = NT_STATUS_NO_LOGON_SERVERS;
		}

		TALLOC_FREE(mutex);
		TALLOC_FREE(frame);
		return result;
	}

	/*
	 * We now have an anonymous connection to IPC$ on the domain password server.
	 */

	ok = get_trust_pw_hash(domain,
			       current_nt_hash.hash,
			       &_account_name,
			       &sec_chan_type);
	if (!ok) {
		cli_shutdown(cli);
		TALLOC_FREE(mutex);
		TALLOC_FREE(frame);
		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
	}

	account_name = talloc_asprintf(talloc_tos(), "%s$", _account_name);
	if (account_name == NULL) {
		cli_shutdown(cli);
		TALLOC_FREE(mutex);
		TALLOC_FREE(frame);
		return NT_STATUS_NO_MEMORY;
	}

	result = rpccli_create_netlogon_creds(dc_name,
					      domain,
					      account_name,
					      sec_chan_type,
					      msg_ctx,
					      talloc_tos(),
					      &netlogon_creds);
	if (!NT_STATUS_IS_OK(result)) {
		cli_shutdown(cli);
		TALLOC_FREE(mutex);
		TALLOC_FREE(frame);
		SAFE_FREE(previous_nt_hash);
		return result;
	}

	result = rpccli_setup_netlogon_creds(cli,
					     netlogon_creds,
					     false, /* force_reauth */
					     current_nt_hash,
					     previous_nt_hash);
	SAFE_FREE(previous_nt_hash);
	if (!NT_STATUS_IS_OK(result)) {
		cli_shutdown(cli);
		TALLOC_FREE(mutex);
		TALLOC_FREE(frame);
		return result;
	}

	result = netlogon_creds_cli_get(netlogon_creds,
					talloc_tos(),
					&creds);
	if (!NT_STATUS_IS_OK(result)) {
		cli_shutdown(cli);
		TALLOC_FREE(mutex);
		TALLOC_FREE(frame);
		return result;
	}
	netlogon_flags = creds->negotiate_flags;
	TALLOC_FREE(creds);

	if (netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
		result = cli_rpc_pipe_open_schannel_with_key(
			cli, &ndr_table_netlogon, NCACN_NP,
			domain, netlogon_creds, &netlogon_pipe);
	} else {
		result = cli_rpc_pipe_open_noauth(cli,
					&ndr_table_netlogon,
					&netlogon_pipe);
	}

	if (!NT_STATUS_IS_OK(result)) {
		DEBUG(0,("connect_to_domain_password_server: "
			 "unable to open the domain client session to "
			 "machine %s. Flags[0x%08X] Error was : %s.\n",
			 dc_name, (unsigned)netlogon_flags,
			 nt_errstr(result)));
		cli_shutdown(cli);
		TALLOC_FREE(mutex);
		TALLOC_FREE(frame);
		return result;
	}

	if(!netlogon_pipe) {
		DEBUG(0, ("connect_to_domain_password_server: unable to open "
			  "the domain client session to machine %s. Error "
			  "was : %s.\n", dc_name, nt_errstr(result)));
		cli_shutdown(cli);
		TALLOC_FREE(mutex);
		TALLOC_FREE(frame);
		return NT_STATUS_NO_LOGON_SERVERS;
	}

	/* We exit here with the mutex *locked*. JRA */

	*cli_ret = cli;
	*pipe_ret = netlogon_pipe;
	*creds_ret = talloc_move(mem_ctx, &netlogon_creds);

	TALLOC_FREE(frame);
	return NT_STATUS_OK;
}