Beispiel #1
0
NTSTATUS rpccli_setup_netlogon_creds_with_creds(struct cli_state *cli,
						enum dcerpc_transport_t transport,
						struct netlogon_creds_cli_context *netlogon_creds,
						bool force_reauth,
						struct cli_credentials *creds)
{
	struct samr_Password *current_nt_hash = NULL;
	struct samr_Password *previous_nt_hash = NULL;
	NTSTATUS status;

	current_nt_hash = cli_credentials_get_nt_hash(creds, talloc_tos());
	if (current_nt_hash == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	previous_nt_hash = cli_credentials_get_old_nt_hash(creds, talloc_tos());

	status = rpccli_setup_netlogon_creds(cli, transport,
					     netlogon_creds,
					     force_reauth,
					     *current_nt_hash,
					     previous_nt_hash);
	TALLOC_FREE(current_nt_hash);
	TALLOC_FREE(previous_nt_hash);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	return NT_STATUS_OK;
}
Beispiel #2
0
static PyObject *py_creds_get_nt_hash(PyObject *self, PyObject *unused)
{
	PyObject *ret;
	struct cli_credentials *creds = PyCredentials_AsCliCredentials(self);
	struct samr_Password *ntpw = cli_credentials_get_nt_hash(creds, creds);

	ret = PyString_FromStringAndSize(discard_const_p(char, ntpw->hash), 16);
	TALLOC_FREE(ntpw);
	return ret;
}
Beispiel #3
0
_PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, 
					   int *flags,
					   DATA_BLOB challenge,
					   const NTTIME *server_timestamp,
					   DATA_BLOB target_info,
					   DATA_BLOB *_lm_response, DATA_BLOB *_nt_response, 
					   DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key) 
{
	const char *user, *domain;
	DATA_BLOB lm_response, nt_response;
	DATA_BLOB lm_session_key, session_key;
	const struct samr_Password *nt_hash;
	lm_session_key = data_blob(NULL, 0);

	/* We may already have an NTLM response we prepared earlier.
	 * This is used for NTLM pass-though authentication */
	if (cred->nt_response.data || cred->lm_response.data) {
		*_nt_response = cred->nt_response;
		*_lm_response = cred->lm_response;

		if (!cred->lm_response.data) {
			*flags = *flags & ~CLI_CRED_LANMAN_AUTH;
		}
		*_lm_session_key = data_blob(NULL, 0);
		*_session_key = data_blob(NULL, 0);
		return NT_STATUS_OK;
	}

	nt_hash = cli_credentials_get_nt_hash(cred, mem_ctx);

	cli_credentials_get_ntlm_username_domain(cred, mem_ctx, &user, &domain);

	/* If we are sending a username@realm login (see function
	 * above), then we will not send LM, it will not be
	 * accepted */
	if (cred->principal_obtained > cred->username_obtained) {
		*flags = *flags & ~CLI_CRED_LANMAN_AUTH;
	}

	/* Likewise if we are a machine account (avoid protocol downgrade attacks) */
	if (cred->machine_account) {
		*flags = *flags & ~CLI_CRED_LANMAN_AUTH;
	}
	
	if (cred->use_kerberos == CRED_MUST_USE_KERBEROS) {
		return NT_STATUS_ACCESS_DENIED;
	}

	if (!nt_hash) {
		static const uint8_t zeros[16];
		/* do nothing - blobs are zero length */

		/* session key is all zeros */
		session_key = data_blob_talloc(mem_ctx, zeros, 16);
		lm_session_key = data_blob_talloc(mem_ctx, zeros, 16);

		lm_response = data_blob(NULL, 0);
		nt_response = data_blob(NULL, 0);
		
		/* not doing NTLM2 without a password */
		*flags &= ~CLI_CRED_NTLM2;
	} else if (*flags & CLI_CRED_NTLMv2_AUTH) {

		if (!target_info.length) {
			/* be lazy, match win2k - we can't do NTLMv2 without it */
			DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
			return NT_STATUS_INVALID_PARAMETER;
		}

		/* TODO: if the remote server is standalone, then we should replace 'domain'
		   with the server name as supplied above */
		
		if (!SMBNTLMv2encrypt_hash(mem_ctx,
					   user, 
					   domain, 
					   nt_hash->hash, &challenge, 
					   server_timestamp, &target_info,
					   &lm_response, &nt_response, 
					   NULL, &session_key)) {
			return NT_STATUS_NO_MEMORY;
		}

		/* LM Key is incompatible... */
		*flags &= ~CLI_CRED_LANMAN_AUTH;
		if (lm_response.length != 0) {
			/*
			 * We should not expose the lm key.
			 */
			memset(lm_response.data, 0, lm_response.length);
		}
	} else if (*flags & CLI_CRED_NTLM2) {
		MD5_CTX md5_session_nonce_ctx;
		uint8_t session_nonce[16];
		uint8_t session_nonce_hash[16];
		uint8_t user_session_key[16];
		
		lm_response = data_blob_talloc(mem_ctx, NULL, 24);
		generate_random_buffer(lm_response.data, 8);
		memset(lm_response.data+8, 0, 16);

		memcpy(session_nonce, challenge.data, 8);
		memcpy(&session_nonce[8], lm_response.data, 8);
	
		MD5Init(&md5_session_nonce_ctx);
		MD5Update(&md5_session_nonce_ctx, challenge.data, 8);
		MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
		MD5Final(session_nonce_hash, &md5_session_nonce_ctx);

		DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
		DEBUG(5, ("challenge is: \n"));
		dump_data(5, session_nonce_hash, 8);
		
		nt_response = data_blob_talloc(mem_ctx, NULL, 24);
		SMBOWFencrypt(nt_hash->hash,
			      session_nonce_hash,
			      nt_response.data);
		
		session_key = data_blob_talloc(mem_ctx, NULL, 16);

		SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
		hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
		dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);

		/* LM Key is incompatible... */
		*flags &= ~CLI_CRED_LANMAN_AUTH;
	} else {
		uint8_t lm_hash[16];
		nt_response = data_blob_talloc(mem_ctx, NULL, 24);
		SMBOWFencrypt(nt_hash->hash, challenge.data,
			      nt_response.data);
		
		session_key = data_blob_talloc(mem_ctx, NULL, 16);
		SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
		dump_data_pw("NT session key:\n", session_key.data, session_key.length);

		/* lanman auth is insecure, it may be disabled.  
		   We may also not have a password */
		if (*flags & CLI_CRED_LANMAN_AUTH) {
			const char *password;
			password = cli_credentials_get_password(cred);
			if (!password) {
				lm_response = nt_response;
			} else {
				lm_response = data_blob_talloc(mem_ctx, NULL, 24);
				if (!SMBencrypt(password,challenge.data,
						lm_response.data)) {
					/* If the LM password was too long (and therefore the LM hash being
					   of the first 14 chars only), don't send it.

					   We don't have any better options but to send the NT response 
					*/
					data_blob_free(&lm_response);
					lm_response = nt_response;
					/* LM Key is incompatible with 'long' passwords */
					*flags &= ~CLI_CRED_LANMAN_AUTH;
				} else if (E_deshash(password, lm_hash)) {
					lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
					memcpy(lm_session_key.data, lm_hash, 8);
					memset(&lm_session_key.data[8], '\0', 8);
					
					if (!(*flags & CLI_CRED_NTLM_AUTH)) {
						session_key = lm_session_key;
					}
				}
			}
		} else {
			const char *password;

			/* LM Key is incompatible... */
			lm_response = nt_response;
			*flags &= ~CLI_CRED_LANMAN_AUTH;

			password = cli_credentials_get_password(cred);
			if (password && E_deshash(password, lm_hash)) {
				lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
				memcpy(lm_session_key.data, lm_hash, 8);
				memset(&lm_session_key.data[8], '\0', 8);
			}
		}
	}
	if (_lm_response) {
		*_lm_response = lm_response;
	}
	if (_nt_response) {
		*_nt_response = nt_response;
	}
	if (_lm_session_key) {
		*_lm_session_key = lm_session_key;
	}
	if (_session_key) {
		*_session_key = session_key;
	}
	return NT_STATUS_OK;
}
Beispiel #4
0
 krb5_error_code kinit_to_ccache(TALLOC_CTX *parent_ctx,
				 struct cli_credentials *credentials,
				 struct smb_krb5_context *smb_krb5_context,
				 struct tevent_context *event_ctx,
				 krb5_ccache ccache,
				 enum credentials_obtained *obtained,
				 const char **error_string)
{
	krb5_error_code ret;
	const char *password;
#ifdef SAMBA4_USES_HEIMDAL
	const char *self_service;
#endif
	const char *target_service;
	time_t kdc_time = 0;
	krb5_principal princ;
	krb5_principal impersonate_principal;
	int tries;
	TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
	krb5_get_init_creds_opt *krb_options;

	if (!mem_ctx) {
		(*error_string) = strerror(ENOMEM);
		return ENOMEM;
	}

	ret = principal_from_credentials(mem_ctx, credentials, smb_krb5_context, &princ, obtained, error_string);
	if (ret) {
		talloc_free(mem_ctx);
		return ret;
	}

	if (princ == NULL) {
		(*error_string) = talloc_asprintf(credentials, "principal, username or realm was not specified in the credentials");
		talloc_free(mem_ctx);
		return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
	}

	ret = impersonate_principal_from_credentials(mem_ctx, credentials, smb_krb5_context, &impersonate_principal, error_string);
	if (ret) {
		talloc_free(mem_ctx);
		return ret;
	}

#ifdef SAMBA4_USES_HEIMDAL
	self_service = cli_credentials_get_self_service(credentials);
#endif
	target_service = cli_credentials_get_target_service(credentials);

	password = cli_credentials_get_password(credentials);

	/* setup the krb5 options we want */
	if ((ret = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context, &krb_options))) {
		(*error_string) = talloc_asprintf(credentials, "krb5_get_init_creds_opt_alloc failed (%s)\n",
						  smb_get_krb5_error_message(smb_krb5_context->krb5_context,
									     ret, mem_ctx));
		talloc_free(mem_ctx);
		return ret;
	}

#ifdef SAMBA4_USES_HEIMDAL /* Disable for now MIT reads defaults when needed */
	/* get the defaults */
	krb5_get_init_creds_opt_set_default_flags(smb_krb5_context->krb5_context, NULL, NULL, krb_options);
#endif
	/* set if we want a forwardable ticket */
	switch (cli_credentials_get_krb_forwardable(credentials)) {
	case CRED_AUTO_KRB_FORWARDABLE:
		break;
	case CRED_NO_KRB_FORWARDABLE:
		krb5_get_init_creds_opt_set_forwardable(krb_options, FALSE);
		break;
	case CRED_FORCE_KRB_FORWARDABLE:
		krb5_get_init_creds_opt_set_forwardable(krb_options, TRUE);
		break;
	}

#ifdef SAMBA4_USES_HEIMDAL /* FIXME: MIT does not have this yet */
	/*
	 * In order to work against windows KDCs even if we use
	 * the netbios domain name as realm, we need to add the following
	 * flags:
	 * KRB5_INIT_CREDS_NO_C_CANON_CHECK;
	 * KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK;
	 *
	 * On MIT: Set pkinit_eku_checking to none
	 */
	krb5_get_init_creds_opt_set_win2k(smb_krb5_context->krb5_context,
					  krb_options, true);
#else /* MIT */
	krb5_get_init_creds_opt_set_canonicalize(krb_options, true);
#endif

	tries = 2;
	while (tries--) {
#ifdef SAMBA4_USES_HEIMDAL
		struct tevent_context *previous_ev;
		/* Do this every time, in case we have weird recursive issues here */
		ret = smb_krb5_context_set_event_ctx(smb_krb5_context, event_ctx, &previous_ev);
		if (ret) {
			talloc_free(mem_ctx);
			return ret;
		}
#endif
		if (password) {
			if (impersonate_principal) {
#ifdef SAMBA4_USES_HEIMDAL
				ret = kerberos_kinit_s4u2_cc(
						smb_krb5_context->krb5_context,
						ccache, princ, password,
						impersonate_principal,
						self_service, target_service,
						krb_options, NULL, &kdc_time);
#else
				talloc_free(mem_ctx);
				(*error_string) = "INTERNAL error: s4u2 ops "
					"are not supported with MIT build yet";
				return EINVAL;
#endif
			} else {
				ret = kerberos_kinit_password_cc(
						smb_krb5_context->krb5_context,
						ccache, princ, password,
						target_service,
						krb_options, NULL, &kdc_time);
			}
		} else if (impersonate_principal) {
			talloc_free(mem_ctx);
			(*error_string) = "INTERNAL error: Cannot impersonate principal with just a keyblock.  A password must be specified in the credentials";
			return EINVAL;
		} else {
			/* No password available, try to use a keyblock instead */
			
			krb5_keyblock keyblock;
			const struct samr_Password *mach_pwd;
			mach_pwd = cli_credentials_get_nt_hash(credentials, mem_ctx);
			if (!mach_pwd) {
				talloc_free(mem_ctx);
				(*error_string) = "kinit_to_ccache: No password available for kinit\n";
				krb5_get_init_creds_opt_free(smb_krb5_context->krb5_context, krb_options);
#ifdef SAMBA4_USES_HEIMDAL
				smb_krb5_context_remove_event_ctx(smb_krb5_context, previous_ev, event_ctx);
#endif
				return EINVAL;
			}
			ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
						 ENCTYPE_ARCFOUR_HMAC,
						 mach_pwd->hash, sizeof(mach_pwd->hash), 
						 &keyblock);
			
			if (ret == 0) {
				ret = kerberos_kinit_keyblock_cc(smb_krb5_context->krb5_context, ccache, 
								 princ, &keyblock,
								 target_service, krb_options,
								 NULL, &kdc_time);
				krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &keyblock);
			}
		}

#ifdef SAMBA4_USES_HEIMDAL
		smb_krb5_context_remove_event_ctx(smb_krb5_context, previous_ev, event_ctx);
#endif

		if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) {
			/* Perhaps we have been given an invalid skew, so try again without it */
			time_t t = time(NULL);
			krb5_set_real_time(smb_krb5_context->krb5_context, t, 0);
		} else {
			/* not a skew problem */
			break;
		}
	}

	krb5_get_init_creds_opt_free(smb_krb5_context->krb5_context, krb_options);

	if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) {
		(*error_string) = talloc_asprintf(credentials, "kinit for %s failed (%s)\n",
						  cli_credentials_get_principal(credentials, mem_ctx),
						  smb_get_krb5_error_message(smb_krb5_context->krb5_context,
									     ret, mem_ctx));
		talloc_free(mem_ctx);
		return ret;
	}

	/* cope with ticket being in the future due to clock skew */
	if ((unsigned)kdc_time > time(NULL)) {
		time_t t = time(NULL);
		int time_offset =(unsigned)kdc_time-t;
		DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset));
		krb5_set_real_time(smb_krb5_context->krb5_context, t + time_offset + 1, 0);
	}
	
	if (ret == KRB5KDC_ERR_PREAUTH_FAILED && cli_credentials_wrong_password(credentials)) {
		ret = kinit_to_ccache(parent_ctx,
				      credentials,
				      smb_krb5_context,
				      event_ctx,
				      ccache, obtained,
				      error_string);
	}

	if (ret) {
		(*error_string) = talloc_asprintf(credentials, "kinit for %s failed (%s)\n",
						  cli_credentials_get_principal(credentials, mem_ctx),
						  smb_get_krb5_error_message(smb_krb5_context->krb5_context,
									     ret, mem_ctx));
		talloc_free(mem_ctx);
		return ret;
	}

	DEBUG(10,("kinit for %s succeeded\n",
		cli_credentials_get_principal(credentials, mem_ctx)));


	talloc_free(mem_ctx);
	return 0;
}
Beispiel #5
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;
}
Beispiel #6
0
 krb5_error_code kinit_to_ccache(TALLOC_CTX *parent_ctx,
				 struct cli_credentials *credentials,
				 struct smb_krb5_context *smb_krb5_context,
				 krb5_ccache ccache) 
{
	krb5_error_code ret;
	const char *password;
	time_t kdc_time = 0;
	krb5_principal princ;
	int tries;
	TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);

	if (!mem_ctx) {
		return ENOMEM;
	}

	ret = principal_from_credentials(mem_ctx, credentials, smb_krb5_context, &princ);
	if (ret) {
		talloc_free(mem_ctx);
		return ret;
	}

	password = cli_credentials_get_password(credentials);

	tries = 2;
	while (tries--) {
		if (password) {
			ret = kerberos_kinit_password_cc(smb_krb5_context->krb5_context, ccache, 
							 princ, 
							 password, NULL, &kdc_time);
		} else {
			/* No password available, try to use a keyblock instead */
			
			krb5_keyblock keyblock;
			const struct samr_Password *mach_pwd;
			mach_pwd = cli_credentials_get_nt_hash(credentials, mem_ctx);
			if (!mach_pwd) {
				talloc_free(mem_ctx);
				DEBUG(1, ("kinit_to_ccache: No password available for kinit\n"));
				return EINVAL;
			}
			ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
						 ENCTYPE_ARCFOUR_HMAC,
						 mach_pwd->hash, sizeof(mach_pwd->hash), 
						 &keyblock);
			
			if (ret == 0) {
				ret = kerberos_kinit_keyblock_cc(smb_krb5_context->krb5_context, ccache, 
								 princ,
								 &keyblock, NULL, &kdc_time);
				krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &keyblock);
			}
		}

		if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) {
			/* Perhaps we have been given an invalid skew, so try again without it */
			time_t t = time(NULL);
			krb5_set_real_time(smb_krb5_context->krb5_context, t, 0);
		} else {
			/* not a skew problem */
			break;
		}
	}

	if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) {
		DEBUG(1,("kinit for %s failed (%s)\n", 
			 cli_credentials_get_principal(credentials, mem_ctx), 
			 smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
						    ret, mem_ctx)));
		talloc_free(mem_ctx);
		return ret;
	}

	/* cope with ticket being in the future due to clock skew */
	if ((unsigned)kdc_time > time(NULL)) {
		time_t t = time(NULL);
		int time_offset =(unsigned)kdc_time-t;
		DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset));
		krb5_set_real_time(smb_krb5_context->krb5_context, t + time_offset + 1, 0);
	}
	
	if (ret == KRB5KDC_ERR_PREAUTH_FAILED && cli_credentials_wrong_password(credentials)) {
		ret = kinit_to_ccache(parent_ctx,
				      credentials,
				      smb_krb5_context,
				      ccache); 
	}
	if (ret) {
		DEBUG(1,("kinit for %s failed (%s)\n", 
			 cli_credentials_get_principal(credentials, mem_ctx), 
			 smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
						    ret, mem_ctx)));
		talloc_free(mem_ctx);
		return ret;
	} 
	talloc_free(mem_ctx);
	return 0;
}
Beispiel #7
0
static PyObject *py_creds_get_nt_hash(pytalloc_Object *self)
{
	const struct samr_Password *ntpw = cli_credentials_get_nt_hash(PyCredentials_AsCliCredentials(self), self->ptr);

	return PyString_FromStringAndSize(discard_const_p(char, ntpw->hash), 16);
}
static int create_keytab(TALLOC_CTX *parent_ctx,
			 struct cli_credentials *machine_account,
			 struct smb_krb5_context *smb_krb5_context,
			 const char **enctype_strings,
			 krb5_keytab keytab,
			 BOOL add_old) 
{
	krb5_error_code ret;
	const char *password_s;
	const char *old_secret;
	int kvno;
	krb5_principal salt_princ;
	krb5_principal princ;
	const char *princ_string;

	TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
	if (!mem_ctx) {
		return ENOMEM;
	}

	princ_string = cli_credentials_get_principal(machine_account, mem_ctx);
	/* Get the principal we will store the new keytab entries under */
	ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &princ);
	if (ret) {
		DEBUG(1,("create_keytab: makeing krb5 principal failed (%s)\n",
			 smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
						    ret, mem_ctx)));
		talloc_free(mem_ctx);
		return ret;
	}

	/* The salt used to generate these entries may be different however, fetch that */
	ret = salt_principal_from_credentials(mem_ctx, machine_account, 
					      smb_krb5_context, 
					      &salt_princ);
	if (ret) {
		DEBUG(1,("create_keytab: makeing salt principal failed (%s)\n",
			 smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
						    ret, mem_ctx)));
		talloc_free(mem_ctx);
		return ret;
	}

	/* Finally, do the dance to get the password to put in the entry */
	password_s = cli_credentials_get_password(machine_account);
	if (!password_s) {
		krb5_keytab_entry entry;
		const struct samr_Password *mach_pwd;

		if (!str_list_check(enctype_strings, "arcfour-hmac-md5")) {
			DEBUG(1, ("Asked to create keytab, but with only an NT hash supplied, "
				  "but not listing arcfour-hmac-md5 as an enc type to include in the keytab!\n"));
			talloc_free(mem_ctx);
			return EINVAL;
		}

		/* If we don't have the plaintext password, try for
		 * the MD4 password hash */
		mach_pwd = cli_credentials_get_nt_hash(machine_account, mem_ctx);
		if (!mach_pwd) {
			/* OK, nothing to do here */
			talloc_free(mem_ctx);
			return 0;
		}
		ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
					 ETYPE_ARCFOUR_HMAC_MD5,
					 mach_pwd->hash, sizeof(mach_pwd->hash), 
					 &entry.keyblock);
		if (ret) {
			DEBUG(1, ("create_keytab: krb5_keyblock_init failed: %s\n",
				  smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
							     ret, mem_ctx)));
			talloc_free(mem_ctx);
			return ret;
		}

		entry.principal = princ;
		entry.vno       = cli_credentials_get_kvno(machine_account);
		ret = krb5_kt_add_entry(smb_krb5_context->krb5_context, keytab, &entry);
		if (ret) {
			DEBUG(1, ("Failed to add ARCFOUR_HMAC (only) entry for %s to keytab: %s",
				  cli_credentials_get_principal(machine_account, mem_ctx), 
				  smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
							     ret, mem_ctx)));
			talloc_free(mem_ctx);
			krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock);
			return ret;
		}
		
		DEBUG(5, ("Added %s(kvno %d) to keytab (arcfour-hmac-md5)\n", 
			  cli_credentials_get_principal(machine_account, mem_ctx),
			  cli_credentials_get_kvno(machine_account)));

		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock);

		/* Can't go any further, we only have this one key */
		talloc_free(mem_ctx);
		return 0;
	}
	
	kvno = cli_credentials_get_kvno(machine_account);
	/* good, we actually have the real plaintext */
	ret = keytab_add_keys(mem_ctx, princ_string, princ, salt_princ, 
			      kvno, password_s, smb_krb5_context, 
			      enctype_strings, keytab);
	if (!ret) {
		talloc_free(mem_ctx);
		return ret;
	}

	if (!add_old || kvno == 0) {
		talloc_free(mem_ctx);
		return 0;
	}

	old_secret = cli_credentials_get_old_password(machine_account);
	if (!old_secret) {
		talloc_free(mem_ctx);
		return 0;
	}
	
	ret = keytab_add_keys(mem_ctx, princ_string, princ, salt_princ, 
			      kvno - 1, old_secret, smb_krb5_context, 
			      enctype_strings, keytab);
	if (!ret) {
		talloc_free(mem_ctx);
		return ret;
	}

	talloc_free(mem_ctx);
	return 0;
}
Beispiel #9
0
NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
				  TALLOC_CTX *out_mem_ctx,
				  const DATA_BLOB in, DATA_BLOB *out)
{
	struct gensec_ntlmssp_context *gensec_ntlmssp =
		talloc_get_type_abort(gensec_security->private_data,
				      struct gensec_ntlmssp_context);
	struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
	uint32_t chal_flags, ntlmssp_command, unkn1 = 0, unkn2 = 0;
	DATA_BLOB server_domain_blob;
	DATA_BLOB challenge_blob;
	DATA_BLOB target_info = data_blob(NULL, 0);
	char *server_domain;
	const char *chal_parse_string;
	const char *chal_parse_string_short = NULL;
	const char *auth_gen_string;
	DATA_BLOB lm_response = data_blob(NULL, 0);
	DATA_BLOB nt_response = data_blob(NULL, 0);
	DATA_BLOB session_key = data_blob(NULL, 0);
	DATA_BLOB lm_session_key = data_blob(NULL, 0);
	DATA_BLOB encrypted_session_key = data_blob(NULL, 0);
	NTSTATUS nt_status;
	int flags = 0;
	const char *user = NULL, *domain = NULL, *workstation = NULL;
	bool is_anonymous = false;
	const DATA_BLOB version_blob = ntlmssp_version_blob();

	TALLOC_CTX *mem_ctx = talloc_new(out_mem_ctx);
	if (!mem_ctx) {
		return NT_STATUS_NO_MEMORY;
	}

	if (!msrpc_parse(mem_ctx,
			 &in, "CdBd",
			 "NTLMSSP",
			 &ntlmssp_command,
			 &server_domain_blob,
			 &chal_flags)) {
		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
		dump_data(2, in.data, in.length);
		talloc_free(mem_ctx);

		return NT_STATUS_INVALID_PARAMETER;
	}

	data_blob_free(&server_domain_blob);

	DEBUG(3, ("Got challenge flags:\n"));
	debug_ntlmssp_flags(chal_flags);

	ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, ntlmssp_state->allow_lm_key);

	if (ntlmssp_state->unicode) {
		if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
			chal_parse_string = "CdUdbddB";
		} else {
			chal_parse_string = "CdUdbdd";
			chal_parse_string_short = "CdUdb";
		}
		auth_gen_string = "CdBBUUUBdb";
	} else {
		if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
			chal_parse_string = "CdAdbddB";
		} else {
			chal_parse_string = "CdAdbdd";
			chal_parse_string_short = "CdAdb";
		}

		auth_gen_string = "CdBBAAABdb";
	}

	if (!msrpc_parse(mem_ctx,
			 &in, chal_parse_string,
			 "NTLMSSP",
			 &ntlmssp_command,
			 &server_domain,
			 &chal_flags,
			 &challenge_blob, 8,
			 &unkn1, &unkn2,
			 &target_info)) {

		bool ok = false;

		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));

		if (chal_parse_string_short != NULL) {
			/*
			 * In the case where NTLMSSP_NEGOTIATE_TARGET_INFO
			 * is not used, some NTLMSSP servers don't return
			 * the unused unkn1 and unkn2 fields.
			 * See bug:
			 * https://bugzilla.samba.org/show_bug.cgi?id=10016
			 * for packet traces.
			 * Try and parse again without them.
			 */
			ok = msrpc_parse(mem_ctx,
				&in, chal_parse_string_short,
				"NTLMSSP",
				&ntlmssp_command,
				&server_domain,
				&chal_flags,
				&challenge_blob, 8);
			if (!ok) {
				DEBUG(1, ("Failed to short parse "
					"the NTLMSSP Challenge: (#2)\n"));
			}
		}

		if (!ok) {
			dump_data(2, in.data, in.length);
			talloc_free(mem_ctx);
			return NT_STATUS_INVALID_PARAMETER;
		}
	}

	if (chal_flags & NTLMSSP_TARGET_TYPE_SERVER) {
		ntlmssp_state->server.is_standalone = true;
	} else {
		ntlmssp_state->server.is_standalone = false;
	}
	/* TODO: parse struct_blob and fill in the rest */
	ntlmssp_state->server.netbios_name = "";
	ntlmssp_state->server.netbios_domain = talloc_move(ntlmssp_state, &server_domain);
	ntlmssp_state->server.dns_name = "";
	ntlmssp_state->server.dns_domain = "";

	if (challenge_blob.length != 8) {
		talloc_free(mem_ctx);
		return NT_STATUS_INVALID_PARAMETER;
	}

	is_anonymous = cli_credentials_is_anonymous(gensec_security->credentials);
	cli_credentials_get_ntlm_username_domain(gensec_security->credentials, mem_ctx,
						 &user, &domain);

	workstation = cli_credentials_get_workstation(gensec_security->credentials);

	if (user == NULL) {
		DEBUG(10, ("User is NULL, returning INVALID_PARAMETER\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (domain == NULL) {
		DEBUG(10, ("Domain is NULL, returning INVALID_PARAMETER\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (workstation == NULL) {
		DEBUG(10, ("Workstation is NULL, returning INVALID_PARAMETER\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (is_anonymous) {
		ntlmssp_state->neg_flags |= NTLMSSP_ANONYMOUS;
		/*
		 * don't use the ccache for anonymous auth
		 */
		ntlmssp_state->use_ccache = false;
	}
	if (ntlmssp_state->use_ccache) {
		struct samr_Password *nt_hash = NULL;

		/*
		 * If we have a password given we don't
		 * use the ccache
		 */
		nt_hash = cli_credentials_get_nt_hash(gensec_security->credentials,
						      mem_ctx);
		if (nt_hash != NULL) {
			ZERO_STRUCTP(nt_hash);
			TALLOC_FREE(nt_hash);
			ntlmssp_state->use_ccache = false;
		}
	}

	if (ntlmssp_state->use_ccache) {
		struct wbcCredentialCacheParams params;
		struct wbcCredentialCacheInfo *info = NULL;
		struct wbcAuthErrorInfo *error = NULL;
		struct wbcNamedBlob auth_blobs[1];
		const struct wbcBlob *wbc_auth_blob = NULL;
		const struct wbcBlob *wbc_session_key = NULL;
		wbcErr wbc_status;
		int i;

		params.account_name = user;
		params.domain_name = domain;
		params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;

		auth_blobs[0].name = "challenge_blob";
		auth_blobs[0].flags = 0;
		auth_blobs[0].blob.data = in.data;
		auth_blobs[0].blob.length = in.length;
		params.num_blobs = ARRAY_SIZE(auth_blobs);
		params.blobs = auth_blobs;

		wbc_status = wbcCredentialCache(&params, &info, &error);
		wbcFreeMemory(error);
		if (!WBC_ERROR_IS_OK(wbc_status)) {
			return NT_STATUS_WRONG_CREDENTIAL_HANDLE;
		}

		for (i=0; i<info->num_blobs; i++) {
			if (strequal(info->blobs[i].name, "auth_blob")) {
				wbc_auth_blob = &info->blobs[i].blob;
			}
			if (strequal(info->blobs[i].name, "session_key")) {
				wbc_session_key = &info->blobs[i].blob;
			}
		}
		if ((wbc_auth_blob == NULL) || (wbc_session_key == NULL)) {
			wbcFreeMemory(info);
			return NT_STATUS_WRONG_CREDENTIAL_HANDLE;
		}

		session_key = data_blob_talloc(mem_ctx,
					       wbc_session_key->data,
					       wbc_session_key->length);
		if (session_key.length != wbc_session_key->length) {
			wbcFreeMemory(info);
			return NT_STATUS_NO_MEMORY;
		}
		*out = data_blob_talloc(mem_ctx,
					wbc_auth_blob->data,
					wbc_auth_blob->length);
		if (out->length != wbc_auth_blob->length) {
			wbcFreeMemory(info);
			return NT_STATUS_NO_MEMORY;
		}

		wbcFreeMemory(info);
		goto done;
	}

	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
		flags |= CLI_CRED_NTLM2;
	}
	if (ntlmssp_state->use_ntlmv2) {
		flags |= CLI_CRED_NTLMv2_AUTH;
	}
	if (ntlmssp_state->use_nt_response) {
		flags |= CLI_CRED_NTLM_AUTH;
	}
	if (lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx)) {
		flags |= CLI_CRED_LANMAN_AUTH;
	}

	nt_status = cli_credentials_get_ntlm_response(gensec_security->credentials, mem_ctx,
						      &flags, challenge_blob, target_info,
						      &lm_response, &nt_response,
						      &lm_session_key, &session_key);

	if (!NT_STATUS_IS_OK(nt_status)) {
		return nt_status;
	}

	if (!(flags & CLI_CRED_LANMAN_AUTH)) {
		/* LM Key is still possible, just silly, so we do not
		 * allow it. Fortunetly all LM crypto is off by
		 * default and we require command line options to end
		 * up here */
		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
	}

	if (!(flags & CLI_CRED_NTLM2)) {
		/* NTLM2 is incompatible... */
		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
	}

	if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
	    && lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx) && lm_session_key.length == 16) {
		DATA_BLOB new_session_key = data_blob_talloc(mem_ctx, NULL, 16);
		if (lm_response.length == 24) {
			SMBsesskeygen_lm_sess_key(lm_session_key.data, lm_response.data,
						  new_session_key.data);
		} else {
			static const uint8_t zeros[24];
			SMBsesskeygen_lm_sess_key(lm_session_key.data, zeros,
						  new_session_key.data);
		}
		session_key = new_session_key;
		dump_data_pw("LM session key\n", session_key.data, session_key.length);
	}


	/* Key exchange encryptes a new client-generated session key with
	   the password-derived key */
	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
		/* Make up a new session key */
		uint8_t client_session_key[16];
		generate_secret_buffer(client_session_key, sizeof(client_session_key));

		/* Encrypt the new session key with the old one */
		encrypted_session_key = data_blob_talloc(ntlmssp_state,
							 client_session_key, sizeof(client_session_key));
		dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length);
		arcfour_crypt(encrypted_session_key.data, session_key.data, encrypted_session_key.length);
		dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);

		/* Mark the new session key as the 'real' session key */
		session_key = data_blob_talloc(mem_ctx, client_session_key, sizeof(client_session_key));
	}

	/* this generates the actual auth packet */
	nt_status = msrpc_gen(mem_ctx,
		       out, auth_gen_string,
		       "NTLMSSP",
		       NTLMSSP_AUTH,
		       lm_response.data, lm_response.length,
		       nt_response.data, nt_response.length,
		       domain,
		       user,
		       workstation,
		       encrypted_session_key.data, encrypted_session_key.length,
		       ntlmssp_state->neg_flags,
		       version_blob.data, version_blob.length);
	if (!NT_STATUS_IS_OK(nt_status)) {
		talloc_free(mem_ctx);
		return nt_status;
	}

done:
	ntlmssp_state->session_key = session_key;
	talloc_steal(ntlmssp_state, session_key.data);

	DEBUG(3, ("NTLMSSP: Set final flags:\n"));
	debug_ntlmssp_flags(ntlmssp_state->neg_flags);

	talloc_steal(out_mem_ctx, out->data);

	ntlmssp_state->expected_state = NTLMSSP_DONE;

	if (gensec_security->want_features & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL)) {
		nt_status = ntlmssp_sign_init(ntlmssp_state);
		if (!NT_STATUS_IS_OK(nt_status)) {
			DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n",
				  nt_errstr(nt_status)));
			talloc_free(mem_ctx);
			return nt_status;
		}
	}

	talloc_free(mem_ctx);
	return NT_STATUS_OK;
}
Beispiel #10
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;
}