Example #1
0
NTSTATUS rpccli_create_netlogon_creds_ctx(
	struct cli_credentials *creds,
	const char *server_computer,
	struct messaging_context *msg_ctx,
	TALLOC_CTX *mem_ctx,
	struct netlogon_creds_cli_context **creds_ctx)
{
	enum netr_SchannelType sec_chan_type;
	const char *server_netbios_domain;
	const char *server_dns_domain;
	const char *client_account;

	sec_chan_type = cli_credentials_get_secure_channel_type(creds);
	client_account = cli_credentials_get_username(creds);
	server_netbios_domain = cli_credentials_get_domain(creds);
	server_dns_domain = cli_credentials_get_realm(creds);

	return rpccli_create_netlogon_creds(server_computer,
					    server_netbios_domain,
					    server_dns_domain,
					    client_account,
					    sec_chan_type,
					    msg_ctx, mem_ctx,
					    creds_ctx);
}
Example #2
0
NTSTATUS rpccli_create_netlogon_creds_with_creds(struct cli_credentials *creds,
						 const char *server_computer,
						 struct messaging_context *msg_ctx,
						 TALLOC_CTX *mem_ctx,
						 struct netlogon_creds_cli_context **netlogon_creds)
{
	enum netr_SchannelType sec_chan_type;
	const char *server_netbios_domain;
	const char *client_account;

	sec_chan_type = cli_credentials_get_secure_channel_type(creds);
	if (sec_chan_type == SEC_CHAN_NULL) {
		return NT_STATUS_INVALID_PARAMETER_MIX;
	}

	client_account = cli_credentials_get_username(creds);
	server_netbios_domain = cli_credentials_get_domain(creds);

	return rpccli_create_netlogon_creds(server_computer,
					    server_netbios_domain,
					    client_account,
					    sec_chan_type,
					    msg_ctx, mem_ctx,
					    netlogon_creds);
}
Example #3
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;
}
Example #4
0
NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_SamSync *r)
{
	NTSTATUS nt_status, dbsync_nt_status;
	TALLOC_CTX *samsync_ctx, *loop_ctx, *delta_ctx;
	struct netlogon_creds_CredentialState *creds;
	struct netr_DatabaseSync dbsync;
	struct netr_Authenticator credential, return_authenticator;
	struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
	struct cli_credentials *machine_account;
	struct dcerpc_pipe *p;
	struct libnet_context *machine_net_ctx;
	struct libnet_RpcConnect *c;
	struct libnet_SamSync_state *state;
	const enum netr_SamDatabaseID database_ids[] = {SAM_DATABASE_DOMAIN, SAM_DATABASE_BUILTIN, SAM_DATABASE_PRIVS}; 
	unsigned int i;

	samsync_ctx = talloc_named(mem_ctx, 0, "SamSync top context");

	if (!r->in.machine_account) { 
		machine_account = cli_credentials_init(samsync_ctx);
		if (!machine_account) {
			talloc_free(samsync_ctx);
			return NT_STATUS_NO_MEMORY;
		}
		cli_credentials_set_conf(machine_account, ctx->lp_ctx);
		nt_status = cli_credentials_set_machine_account(machine_account, ctx->lp_ctx);
		if (!NT_STATUS_IS_OK(nt_status)) {
			r->out.error_string = talloc_strdup(mem_ctx, "Could not obtain machine account password - are we joined to the domain?");
			talloc_free(samsync_ctx);
			return nt_status;
		}
	} else {
		machine_account = r->in.machine_account;
	}

	/* We cannot do this unless we are a BDC.  Check, before we get odd errors later */
	if (cli_credentials_get_secure_channel_type(machine_account) != SEC_CHAN_BDC) {
		r->out.error_string
			= talloc_asprintf(mem_ctx, 
					  "Our join to domain %s is not as a BDC (%d), please rejoin as a BDC",
					  cli_credentials_get_domain(machine_account),
					  cli_credentials_get_secure_channel_type(machine_account));
		talloc_free(samsync_ctx);
		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
	}

	c = talloc_zero(samsync_ctx, struct libnet_RpcConnect);
	if (!c) {
		r->out.error_string = NULL;
		talloc_free(samsync_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	c->level              = LIBNET_RPC_CONNECT_DC_INFO;
	if (r->in.binding_string) {
		c->in.binding = r->in.binding_string;
		c->in.name    = NULL;
	} else {
		c->in.binding = NULL;
		c->in.name    = cli_credentials_get_domain(machine_account);
	}
	
	/* prepare connect to the NETLOGON pipe of PDC */
	c->in.dcerpc_iface      = &ndr_table_netlogon;

	/* We must do this as the machine, not as any command-line
	 * user.  So we override the credentials in the
	 * libnet_context */
	machine_net_ctx = talloc(samsync_ctx, struct libnet_context);
	if (!machine_net_ctx) {
		r->out.error_string = NULL;
		talloc_free(samsync_ctx);
		return NT_STATUS_NO_MEMORY;
	}
	*machine_net_ctx = *ctx;
	machine_net_ctx->cred = machine_account;

	/* connect to the NETLOGON pipe of the PDC */
	nt_status = libnet_RpcConnect(machine_net_ctx, samsync_ctx, c);
	if (!NT_STATUS_IS_OK(nt_status)) {
		if (r->in.binding_string) {
			r->out.error_string = talloc_asprintf(mem_ctx,
							      "Connection to NETLOGON pipe of DC %s failed: %s",
							      r->in.binding_string, c->out.error_string);
		} else {
			r->out.error_string = talloc_asprintf(mem_ctx,
							      "Connection to NETLOGON pipe of DC for %s failed: %s",
							      c->in.name, c->out.error_string);
		}
		talloc_free(samsync_ctx);
		return nt_status;
	}

	/* This makes a new pipe, on which we can do schannel.  We
	 * should do this in the RpcConnect code, but the abstaction
	 * layers do not suit yet */

	nt_status = dcerpc_secondary_connection(c->out.dcerpc_pipe, &p,
						c->out.dcerpc_pipe->binding);

	if (!NT_STATUS_IS_OK(nt_status)) {
		r->out.error_string = talloc_asprintf(mem_ctx,
						      "Secondary connection to NETLOGON pipe of DC %s failed: %s",
						      dcerpc_server_name(p), nt_errstr(nt_status));
		talloc_free(samsync_ctx);
		return nt_status;
	}

	nt_status = dcerpc_bind_auth_schannel(samsync_ctx, p, &ndr_table_netlogon,
					      machine_account, ctx->lp_ctx, DCERPC_AUTH_LEVEL_PRIVACY);

	if (!NT_STATUS_IS_OK(nt_status)) {
		r->out.error_string = talloc_asprintf(mem_ctx,
						      "SCHANNEL authentication to NETLOGON pipe of DC %s failed: %s",
						      dcerpc_server_name(p), nt_errstr(nt_status));
		talloc_free(samsync_ctx);
		return nt_status;
	}

	state = talloc(samsync_ctx, struct libnet_SamSync_state);
	if (!state) {
		r->out.error_string = NULL;
		talloc_free(samsync_ctx);
		return nt_status;
	}		

	state->domain_name     = c->out.domain_name;
	state->domain_sid      = c->out.domain_sid;
	state->realm           = c->out.realm;
	state->domain_guid     = c->out.guid;
	state->machine_net_ctx = machine_net_ctx;
	state->netlogon_pipe   = p;

	/* initialise the callback layer.  It may wish to contact the
	 * server with ldap, now we know the name */
	
	if (r->in.init_fn) {
		char *error_string;
		nt_status = r->in.init_fn(samsync_ctx, 
					  r->in.fn_ctx,
					  state, 
					  &error_string); 
		if (!NT_STATUS_IS_OK(nt_status)) {
			r->out.error_string = talloc_steal(mem_ctx, error_string);
			talloc_free(samsync_ctx);
			return nt_status;
		}
	}

	/* get NETLOGON credentials */

	nt_status = dcerpc_schannel_creds(p->conn->security_state.generic_state, samsync_ctx, &creds);
	if (!NT_STATUS_IS_OK(nt_status)) {
		r->out.error_string = talloc_strdup(mem_ctx, "Could not obtain NETLOGON credentials from DCERPC/GENSEC layer");
		talloc_free(samsync_ctx);
		return nt_status;
	}

	/* Setup details for the synchronisation */

	ZERO_STRUCT(return_authenticator);

	dbsync.in.logon_server = talloc_asprintf(samsync_ctx, "\\\\%s", dcerpc_server_name(p));
	dbsync.in.computername = cli_credentials_get_workstation(machine_account);
	dbsync.in.preferredmaximumlength = (uint32_t)-1;
	dbsync.in.return_authenticator = &return_authenticator;
	dbsync.out.return_authenticator = &return_authenticator;
	dbsync.out.delta_enum_array = &delta_enum_array;

	for (i=0;i< ARRAY_SIZE(database_ids); i++) {

		uint32_t sync_context = 0;

		dbsync.in.database_id = database_ids[i];
		dbsync.in.sync_context = &sync_context;
		dbsync.out.sync_context = &sync_context;
		
		do {
			uint32_t d;
			loop_ctx = talloc_named(samsync_ctx, 0, "DatabaseSync loop context");
			netlogon_creds_client_authenticator(creds, &credential);

			dbsync.in.credential = &credential;
			
			dbsync_nt_status = dcerpc_netr_DatabaseSync_r(p->binding_handle, loop_ctx, &dbsync);
			if (NT_STATUS_IS_OK(dbsync_nt_status) && !NT_STATUS_IS_OK(dbsync.out.result)) {
				dbsync_nt_status = dbsync.out.result;
			}
			if (!NT_STATUS_IS_OK(dbsync_nt_status) &&
			    !NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES)) {
				r->out.error_string = talloc_asprintf(mem_ctx, "DatabaseSync failed - %s", nt_errstr(nt_status));
				talloc_free(samsync_ctx);
				return nt_status;
			}
			
			if (!netlogon_creds_client_check(creds, &dbsync.out.return_authenticator->cred)) {
				r->out.error_string = talloc_strdup(mem_ctx, "Credential chaining on incoming DatabaseSync failed");
				talloc_free(samsync_ctx);
				return NT_STATUS_ACCESS_DENIED;
			}
			
			dbsync.in.sync_context = dbsync.out.sync_context;
			
			/* For every single remote 'delta' entry: */
			for (d=0; d < delta_enum_array->num_deltas; d++) {
				char *error_string = NULL;
				delta_ctx = talloc_named(loop_ctx, 0, "DatabaseSync delta context");
				/* 'Fix' elements, by decrypting and
				 * de-obfuscating the data */
				nt_status = samsync_fix_delta(delta_ctx, 
							      creds, 
							      dbsync.in.database_id,
							      &delta_enum_array->delta_enum[d]);
				if (!NT_STATUS_IS_OK(nt_status)) {
					r->out.error_string = talloc_steal(mem_ctx, error_string);
					talloc_free(samsync_ctx);
					return nt_status;
				}

				/* Now call the callback.  This will
				 * do something like print the data or
				 * write to an ldb */
				nt_status = r->in.delta_fn(delta_ctx, 
							   r->in.fn_ctx,
							   dbsync.in.database_id,
							   &delta_enum_array->delta_enum[d],
							   &error_string);
				if (!NT_STATUS_IS_OK(nt_status)) {
					r->out.error_string = talloc_steal(mem_ctx, error_string);
					talloc_free(samsync_ctx);
					return nt_status;
				}
				talloc_free(delta_ctx);
			}
			talloc_free(loop_ctx);
		} while (NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES));
		
		if (!NT_STATUS_IS_OK(dbsync_nt_status)) {
			r->out.error_string = talloc_asprintf(mem_ctx, "libnet_SamSync_netlogon failed: unexpected inconsistancy. Should not get error %s here", nt_errstr(nt_status));
			talloc_free(samsync_ctx);
			return dbsync_nt_status;
		}
		nt_status = NT_STATUS_OK;
	}
	talloc_free(samsync_ctx);
	return nt_status;
}
Example #5
0
NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
			 struct messaging_context *msg_ctx,
			 struct dcerpc_binding_handle *b,
			 const char *domain,
			 bool force)
{
	TALLOC_CTX *frame = talloc_stackframe();
	struct trust_pw_change_state *state;
	struct cli_credentials *creds = NULL;
	const struct samr_Password *current_nt_hash = NULL;
	const struct samr_Password *previous_nt_hash = NULL;
	enum netr_SchannelType sec_channel_type = SEC_CHAN_NULL;
	time_t pass_last_set_time;
	uint32_t old_version = 0;
	struct pdb_trusted_domain *td = NULL;
	struct timeval g_timeout = { 0, };
	int timeout = 0;
	struct timeval tv = { 0, };
	size_t new_len = DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH;
	uint8_t new_password_buffer[256 * 2] = { 0, };
	char *new_trust_passwd = NULL;
	size_t len = 0;
	uint32_t new_version = 0;
	uint32_t *new_trust_version = NULL;
	NTSTATUS status;
	bool ok;

	state = talloc_zero(frame, struct trust_pw_change_state);
	if (state == NULL) {
		TALLOC_FREE(frame);
		return NT_STATUS_NO_MEMORY;
	}

	state->g_ctx = g_lock_ctx_init(state, msg_ctx);
	if (state->g_ctx == NULL) {
		TALLOC_FREE(frame);
		return NT_STATUS_NO_MEMORY;
	}

	state->g_lock_key = talloc_asprintf(state,
				"trust_password_change_%s",
				domain);
	if (state->g_lock_key == NULL) {
		TALLOC_FREE(frame);
		return NT_STATUS_NO_MEMORY;
	}

	g_timeout = timeval_current_ofs(10, 0);
	status = g_lock_lock(state->g_ctx,
			     state->g_lock_key,
			     G_LOCK_WRITE, g_timeout);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("could not get g_lock on [%s]!\n",
			  state->g_lock_key));
		TALLOC_FREE(frame);
		return status;
	}

	talloc_set_destructor(state, trust_pw_change_state_destructor);

	status = pdb_get_trust_credentials(domain, NULL, frame, &creds);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("could not fetch domain creds for domain %s - %s!\n",
			  domain, nt_errstr(status)));
		TALLOC_FREE(frame);
		return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
	}

	current_nt_hash = cli_credentials_get_nt_hash(creds, frame);
	if (current_nt_hash == NULL) {
		DEBUG(0, ("cli_credentials_get_nt_hash failed for domain %s!\n",
			  domain));
		TALLOC_FREE(frame);
		return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
	}

	old_version = cli_credentials_get_kvno(creds);
	pass_last_set_time = cli_credentials_get_password_last_changed_time(creds);
	sec_channel_type = cli_credentials_get_secure_channel_type(creds);

	new_version = old_version + 1;

	switch (sec_channel_type) {
	case SEC_CHAN_WKSTA:
	case SEC_CHAN_BDC:
		break;
	case SEC_CHAN_DNS_DOMAIN:
		/*
		 * new_len * 2 = 498 bytes is the largest possible length
		 * NL_PASSWORD_VERSION consumes the rest of the possible 512 bytes
		 * and a confounder with at least 2 bytes is required.
		 *
		 * Windows uses new_len = 120 => 240 bytes.
		 */
		new_len = 120;

		/* fall through */
	case SEC_CHAN_DOMAIN:
		status = pdb_get_trusted_domain(frame, domain, &td);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0, ("pdb_get_trusted_domain() failed for domain %s - %s!\n",
				  domain, nt_errstr(status)));
			TALLOC_FREE(frame);
			return status;
		}

		new_trust_version = &new_version;
		break;
	default:
		TALLOC_FREE(frame);
		return NT_STATUS_NOT_SUPPORTED;
	}

	timeout = lp_machine_password_timeout();
	if (timeout == 0) {
		if (!force) {
			DEBUG(10,("machine password never expires\n"));
			TALLOC_FREE(frame);
			return NT_STATUS_OK;
		}
	}

	tv.tv_sec = pass_last_set_time;
	DEBUG(10, ("password last changed %s\n",
		   timeval_string(talloc_tos(), &tv, false)));
	tv.tv_sec += timeout;
	DEBUGADD(10, ("password valid until %s\n",
		      timeval_string(talloc_tos(), &tv, false)));

	if (!force && !timeval_expired(&tv)) {
		TALLOC_FREE(frame);
		return NT_STATUS_OK;
	}

	/*
	 * Create a random machine account password
	 * We create a random buffer and convert that to utf8.
	 * This is similar to what windows is doing.
	 */
	generate_secret_buffer(new_password_buffer, new_len * 2);
	ok = convert_string_talloc(frame,
				   CH_UTF16MUNGED, CH_UTF8,
				   new_password_buffer, new_len * 2,
				   (void *)&new_trust_passwd, &len);
	ZERO_STRUCT(new_password_buffer);
	if (!ok) {
		DEBUG(0, ("convert_string_talloc failed\n"));
		TALLOC_FREE(frame);
		return NT_STATUS_NO_MEMORY;
	}

	/*
	 * We could use cli_credentials_get_old_nt_hash(creds, frame) to
	 * set previous_nt_hash.
	 *
	 * But we want to check if the dc has our current password and only do
	 * a change if that's the case. So we keep previous_nt_hash = NULL.
	 *
	 * TODO:
	 * If the previous password is the only password in common with the dc,
	 * we better skip the password change, or use something like
	 * ServerTrustPasswordsGet() or netr_ServerGetTrustInfo() to fix our
	 * local secrets before doing the change.
	 */
	status = netlogon_creds_cli_auth(context, b,
					 *current_nt_hash,
					 previous_nt_hash);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("netlogon_creds_cli_auth for domain %s - %s!\n",
			  domain, nt_errstr(status)));
		TALLOC_FREE(frame);
		return status;
	}

	/*
	 * Return the result of trying to write the new password
	 * back into the trust account file.
	 */

	switch (sec_channel_type) {

	case SEC_CHAN_WKSTA:
	case SEC_CHAN_BDC:
		ok = secrets_store_machine_password(new_trust_passwd, domain, sec_channel_type);
		if (!ok) {
			DEBUG(0, ("secrets_store_machine_password failed for domain %s!\n",
				  domain));
			TALLOC_FREE(frame);
			return NT_STATUS_INTERNAL_DB_CORRUPTION;
		}
		break;

	case SEC_CHAN_DNS_DOMAIN:
	case SEC_CHAN_DOMAIN:
		/*
		 * we need to get the sid first for the
		 * pdb_set_trusteddom_pw call
		 */
		ok = pdb_set_trusteddom_pw(domain, new_trust_passwd,
					   &td->security_identifier);
		if (!ok) {
			DEBUG(0, ("pdb_set_trusteddom_pw() failed for domain %s!\n",
				  domain));
			TALLOC_FREE(frame);
			return NT_STATUS_INTERNAL_DB_CORRUPTION;
		}
		break;

	default:
		smb_panic("Unsupported secure channel type");
		break;
	}

	DEBUG(1,("%s : %s(%s): Changed password locally\n",
		 current_timestring(talloc_tos(), false), __func__, domain));

	status = netlogon_creds_cli_ServerPasswordSet(context, b,
						      new_trust_passwd,
						      new_trust_version);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0,("%s : %s(%s) remote password change set failed - %s\n",
			 current_timestring(talloc_tos(), false), __func__,
			 domain, nt_errstr(status)));
		TALLOC_FREE(frame);
		return status;
	}

	DEBUG(1,("%s : %s(%s): Changed password remotely.\n",
		 current_timestring(talloc_tos(), false), __func__, domain));

	TALLOC_FREE(frame);
	return NT_STATUS_OK;
}