Example #1
0
static NTSTATUS local_pw_check_specified(struct loadparm_context *lp_ctx,
					 const char *username, 
					 const char *domain, 
					 const char *workstation,
					 const DATA_BLOB *challenge, 
					 const DATA_BLOB *lm_response, 
					 const DATA_BLOB *nt_response, 
					 uint32_t flags, 
					 DATA_BLOB *lm_session_key, 
					 DATA_BLOB *user_session_key, 
					 char **error_string, 
					 char **unix_name) 
{
	NTSTATUS nt_status;
	struct samr_Password lm_pw, nt_pw;
	struct samr_Password *lm_pwd, *nt_pwd;
	TALLOC_CTX *mem_ctx = talloc_init("local_pw_check_specified");
	if (!mem_ctx) {
		nt_status = NT_STATUS_NO_MEMORY;
	} else {
		
		E_md4hash(opt_password, nt_pw.hash);
		if (E_deshash(opt_password, lm_pw.hash)) {
			lm_pwd = &lm_pw;
		} else {
			lm_pwd = NULL;
		}
		nt_pwd = &nt_pw;
		
		
		nt_status = ntlm_password_check(mem_ctx, 
						lpcfg_lanman_auth(lp_ctx),
						lpcfg_ntlm_auth(lp_ctx),
						MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
						MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT,
						challenge,
						lm_response,
						nt_response,
						username,
						username,
						domain,
						lm_pwd, nt_pwd, user_session_key, lm_session_key);
		
		if (NT_STATUS_IS_OK(nt_status)) {
			if (unix_name) {
				if (asprintf(unix_name, "%s%c%s", domain,
					     *lpcfg_winbind_separator(lp_ctx),
					     username) < 0) {
					nt_status = NT_STATUS_NO_MEMORY;
				}
			}
		} else {
			DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n", 
				  domain, username, workstation, 
				  nt_errstr(nt_status)));
		}
		talloc_free(mem_ctx);
	}
	if (error_string) {
		*error_string = strdup(nt_errstr(nt_status));
	}
	return nt_status;
	
	
}
Example #2
0
static bool test_wbc_change_password(struct torture_context *tctx)
{
	wbcErr ret;
	const char *oldpass = getenv("PASSWORD");
	const char *newpass = "******";

	struct samr_CryptPassword new_nt_password;
	struct samr_CryptPassword new_lm_password;
	struct samr_Password old_nt_hash_enc;
	struct samr_Password old_lanman_hash_enc;

	uint8_t old_nt_hash[16];
	uint8_t old_lanman_hash[16];
	uint8_t new_nt_hash[16];
	uint8_t new_lanman_hash[16];

	struct wbcChangePasswordParams params;

	if (oldpass == NULL) {
		torture_skip(tctx,
			"skipping wbcChangeUserPassword test as old password cannot be retrieved\n");
	}

	ZERO_STRUCT(params);

	E_md4hash(oldpass, old_nt_hash);
	E_md4hash(newpass, new_nt_hash);

	if (lpcfg_client_lanman_auth(tctx->lp_ctx) &&
	    E_deshash(newpass, new_lanman_hash) &&
	    E_deshash(oldpass, old_lanman_hash)) {

		/* E_deshash returns false for 'long' passwords (> 14
		   DOS chars).  This allows us to match Win2k, which
		   does not store a LM hash for these passwords (which
		   would reduce the effective password length to 14) */

		encode_pw_buffer(new_lm_password.data, newpass, STR_UNICODE);
		arcfour_crypt(new_lm_password.data, old_nt_hash, 516);
		E_old_pw_hash(new_nt_hash, old_lanman_hash,
			      old_lanman_hash_enc.hash);

		params.old_password.response.old_lm_hash_enc_length =
			sizeof(old_lanman_hash_enc.hash);
		params.old_password.response.old_lm_hash_enc_data =
			old_lanman_hash_enc.hash;
		params.new_password.response.lm_length =
			sizeof(new_lm_password.data);
		params.new_password.response.lm_data =
			new_lm_password.data;
	} else {
		ZERO_STRUCT(new_lm_password);
		ZERO_STRUCT(old_lanman_hash_enc);
	}

	encode_pw_buffer(new_nt_password.data, newpass, STR_UNICODE);

	arcfour_crypt(new_nt_password.data, old_nt_hash, 516);
	E_old_pw_hash(new_nt_hash, old_nt_hash, old_nt_hash_enc.hash);

	params.old_password.response.old_nt_hash_enc_length =
		sizeof(old_nt_hash_enc.hash);
	params.old_password.response.old_nt_hash_enc_data =
		old_nt_hash_enc.hash;
	params.new_password.response.nt_length = sizeof(new_nt_password.data);
	params.new_password.response.nt_data = new_nt_password.data;

	params.level = WBC_CHANGE_PASSWORD_LEVEL_RESPONSE;
	params.account_name = getenv("USERNAME");
	params.domain_name = "SAMBA-TEST";

	ret = wbcChangeUserPasswordEx(&params, NULL, NULL, NULL);
	torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS,
				 "wbcChangeUserPassword failed");

	if (!test_wbc_authenticate_user_int(tctx, "Koo8irei")) {
		return false;
	}

	ret = wbcChangeUserPassword(getenv("USERNAME"), "Koo8irei",
				    getenv("PASSWORD"));
	torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS,
				 "wbcChangeUserPassword failed");

	return test_wbc_authenticate_user_int(tctx, getenv("PASSWORD"));
}
Example #3
0
NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_context, 
			   enum auth_password_state to_state,
			   const struct auth_usersupplied_info *user_info_in,
			   const struct auth_usersupplied_info **user_info_encrypted)
{
	NTSTATUS nt_status;
	struct auth_usersupplied_info *user_info_temp;
	switch (to_state) {
	case AUTH_PASSWORD_RESPONSE:
		switch (user_info_in->password_state) {
		case AUTH_PASSWORD_PLAIN:
		{
			const struct auth_usersupplied_info *user_info_temp2;
			nt_status = encrypt_user_info(mem_ctx, auth_context, 
						      AUTH_PASSWORD_HASH, 
						      user_info_in, &user_info_temp2);
			if (!NT_STATUS_IS_OK(nt_status)) {
				return nt_status;
			}
			user_info_in = user_info_temp2;
			/* fall through */
		}
		case AUTH_PASSWORD_HASH:
		{
			const uint8_t *challenge;
			DATA_BLOB chall_blob;
			user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info);
			if (!user_info_temp) {
				return NT_STATUS_NO_MEMORY;
			}
			if (!talloc_reference(user_info_temp, user_info_in)) {
				return NT_STATUS_NO_MEMORY;
			}
			*user_info_temp = *user_info_in;
			user_info_temp->mapped_state = to_state;
			
			nt_status = auth_get_challenge(auth_context, &challenge);
			if (!NT_STATUS_IS_OK(nt_status)) {
				return nt_status;
			}
			
			chall_blob = data_blob_talloc(mem_ctx, challenge, 8);
			if (lp_client_ntlmv2_auth(auth_context->lp_ctx)) {
				DATA_BLOB names_blob = NTLMv2_generate_names_blob(mem_ctx,  lp_netbios_name(auth_context->lp_ctx), lp_workgroup(auth_context->lp_ctx));
				DATA_BLOB lmv2_response, ntlmv2_response, lmv2_session_key, ntlmv2_session_key;
				
				if (!SMBNTLMv2encrypt_hash(user_info_temp,
							   user_info_in->client.account_name, 
							   user_info_in->client.domain_name, 
							   user_info_in->password.hash.nt->hash, &chall_blob,
							   &names_blob,
							   &lmv2_response, &ntlmv2_response, 
							   &lmv2_session_key, &ntlmv2_session_key)) {
					data_blob_free(&names_blob);
					return NT_STATUS_NO_MEMORY;
				}
				data_blob_free(&names_blob);
				user_info_temp->password.response.lanman = lmv2_response;
				user_info_temp->password.response.nt = ntlmv2_response;
				
				data_blob_free(&lmv2_session_key);
				data_blob_free(&ntlmv2_session_key);
			} else {
				DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, 24);
				SMBOWFencrypt(user_info_in->password.hash.nt->hash, challenge, blob.data);

				user_info_temp->password.response.nt = blob;
				if (lp_client_lanman_auth(auth_context->lp_ctx) && user_info_in->password.hash.lanman) {
					DATA_BLOB lm_blob = data_blob_talloc(mem_ctx, NULL, 24);
					SMBOWFencrypt(user_info_in->password.hash.lanman->hash, challenge, blob.data);
					user_info_temp->password.response.lanman = lm_blob;
				} else {
					/* if not sending the LM password, send the NT password twice */
					user_info_temp->password.response.lanman = user_info_temp->password.response.nt;
				}
			}

			user_info_in = user_info_temp;
			/* fall through */
		}
		case AUTH_PASSWORD_RESPONSE:
			*user_info_encrypted = user_info_in;
		}
		break;
	case AUTH_PASSWORD_HASH:
	{	
		switch (user_info_in->password_state) {
		case AUTH_PASSWORD_PLAIN:
		{
			struct samr_Password lanman;
			struct samr_Password nt;
			
			user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info);
			if (!user_info_temp) {
				return NT_STATUS_NO_MEMORY;
			}
			if (!talloc_reference(user_info_temp, user_info_in)) {
				return NT_STATUS_NO_MEMORY;
			}
			*user_info_temp = *user_info_in;
			user_info_temp->mapped_state = to_state;
			
			if (E_deshash(user_info_in->password.plaintext, lanman.hash)) {
				user_info_temp->password.hash.lanman = talloc(user_info_temp,
									      struct samr_Password);
				*user_info_temp->password.hash.lanman = lanman;
			} else {
				user_info_temp->password.hash.lanman = NULL;
			}
			
			E_md4hash(user_info_in->password.plaintext, nt.hash);
			user_info_temp->password.hash.nt = talloc(user_info_temp,
								   struct samr_Password);
			*user_info_temp->password.hash.nt = nt;
			
			user_info_in = user_info_temp;
			/* fall through */
		}
		case AUTH_PASSWORD_HASH:
			*user_info_encrypted = user_info_in;
			break;
		default:
			return NT_STATUS_INVALID_PARAMETER;
			break;
		}
		break;
	}
Example #4
0
static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
			    const struct nls_table *nls_cp)
{
	int rc = 0;
	int len;
	char nt_hash[CIFS_NTHASH_SIZE];
	__le16 *user;
	wchar_t *domain;
	wchar_t *server;

	if (!ses->server->secmech.sdeschmacmd5) {
		cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__);
		return -1;
	}

	/* calculate md4 hash of password */
	E_md4hash(ses->password, nt_hash, nls_cp);

	rc = crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash,
				CIFS_NTHASH_SIZE);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not set NT Hash as a key\n", __func__);
		return rc;
	}

	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
	if (rc) {
		cifs_dbg(VFS, "%s: could not init hmacmd5\n", __func__);
		return rc;
	}

	/* convert ses->user_name to unicode */
	len = ses->user_name ? strlen(ses->user_name) : 0;
	user = kmalloc(2 + (len * 2), GFP_KERNEL);
	if (user == NULL) {
		rc = -ENOMEM;
		return rc;
	}

	if (len) {
		len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp);
		UniStrupr(user);
	} else {
		memset(user, '\0', 2);
	}

	rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
				(char *)user, 2 * len);
	kfree(user);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not update with user\n", __func__);
		return rc;
	}

	/* convert ses->domainName to unicode and uppercase */
	if (ses->domainName) {
		len = strlen(ses->domainName);

		domain = kmalloc(2 + (len * 2), GFP_KERNEL);
		if (domain == NULL) {
			rc = -ENOMEM;
			return rc;
		}
		len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len,
				      nls_cp);
		rc =
		crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
					(char *)domain, 2 * len);
		kfree(domain);
		if (rc) {
			cifs_dbg(VFS, "%s: Could not update with domain\n",
				 __func__);
			return rc;
		}
	} else if (ses->serverName) {
		len = strlen(ses->serverName);

		server = kmalloc(2 + (len * 2), GFP_KERNEL);
		if (server == NULL) {
			rc = -ENOMEM;
			return rc;
		}
		len = cifs_strtoUTF16((__le16 *)server, ses->serverName, len,
					nls_cp);
		rc =
		crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
					(char *)server, 2 * len);
		kfree(server);
		if (rc) {
			cifs_dbg(VFS, "%s: Could not update with server\n",
				 __func__);
			return rc;
		}
	}

	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
					ntlmv2_hash);
	if (rc)
		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);

	return rc;
}
Example #5
0
void SMBNTencrypt(const char *passwd, const uint8_t *c8, uint8_t *p24)
{
	uint8_t nt_hash[16];
	E_md4hash(passwd, nt_hash);
	SMBNTencrypt_hash(nt_hash, c8, p24);
}
Example #6
0
static NTSTATUS authsam_password_check_and_record(struct auth4_context *auth_context,
						  TALLOC_CTX *mem_ctx,
						  struct ldb_dn *domain_dn,
						  struct ldb_message *msg,
						  uint16_t acct_flags,
						  const struct auth_usersupplied_info *user_info,
						  DATA_BLOB *user_sess_key,
						  DATA_BLOB *lm_sess_key,
						  bool *authoritative)
{
	NTSTATUS nt_status;
	NTSTATUS auth_status;
	TALLOC_CTX *tmp_ctx;
	int i, ret;
	int history_len = 0;
	struct ldb_context *sam_ctx = auth_context->sam_ctx;
	const char * const attrs[] = { "pwdHistoryLength", NULL };
	struct ldb_message *dom_msg;
	struct samr_Password *lm_pwd;
	struct samr_Password *nt_pwd;
	bool am_rodc;

	tmp_ctx = talloc_new(mem_ctx);
	if (tmp_ctx == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	/*
	 * This call does more than what it appears to do, it also
	 * checks for the account lockout.
	 *
	 * It is done here so that all parts of Samba that read the
	 * password refuse to even operate on it if the account is
	 * locked out, to avoid mistakes like CVE-2013-4496.
	 */
	nt_status = samdb_result_passwords(tmp_ctx, auth_context->lp_ctx,
					   msg, &lm_pwd, &nt_pwd);
	if (!NT_STATUS_IS_OK(nt_status)) {
		TALLOC_FREE(tmp_ctx);
		return nt_status;
	}

	if (lm_pwd == NULL && nt_pwd == NULL) {
		if (samdb_rodc(auth_context->sam_ctx, &am_rodc) == LDB_SUCCESS && am_rodc) {
			/*
			 * we don't have passwords for this
			 * account. We are an RODC, and this account
			 * may be one for which we either are denied
			 * REPL_SECRET replication or we haven't yet
			 * done the replication. We return
			 * NT_STATUS_NOT_IMPLEMENTED which tells the
			 * auth code to try the next authentication
			 * mechanism. We also send a message to our
			 * drepl server to tell it to try and
			 * replicate the secrets for this account.
			 *
			 * TODO: Should we only trigger this is detected
			 * there's a chance that the password might be
			 * replicated, we should be able to detect this
			 * based on msDS-NeverRevealGroup.
			 */
			auth_sam_trigger_repl_secret(auth_context,
						     auth_context->msg_ctx,
						     auth_context->event_ctx,
						     msg->dn);
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NOT_IMPLEMENTED;
		}
	}

	auth_status = authsam_password_ok(auth_context, tmp_ctx,
					  acct_flags,
					  lm_pwd, nt_pwd,
					  user_info,
					  user_sess_key, lm_sess_key);
	if (NT_STATUS_IS_OK(auth_status)) {
		if (user_sess_key->data) {
			talloc_steal(mem_ctx, user_sess_key->data);
		}
		if (lm_sess_key->data) {
			talloc_steal(mem_ctx, lm_sess_key->data);
		}
		TALLOC_FREE(tmp_ctx);
		return NT_STATUS_OK;
	}
	*user_sess_key = data_blob_null;
	*lm_sess_key = data_blob_null;

	if (!NT_STATUS_EQUAL(auth_status, NT_STATUS_WRONG_PASSWORD)) {
		TALLOC_FREE(tmp_ctx);
		return auth_status;
	}

	/*
	 * We only continue if this was a wrong password
	 * and we'll always return NT_STATUS_WRONG_PASSWORD
	 * no matter what error happens.
	 */

	/* pull the domain password property attributes */
	ret = dsdb_search_one(sam_ctx, tmp_ctx, &dom_msg, domain_dn, LDB_SCOPE_BASE,
			      attrs, 0, "objectClass=domain");
	if (ret == LDB_SUCCESS) {
		history_len = ldb_msg_find_attr_as_uint(dom_msg, "pwdHistoryLength", 0);
	} else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		DEBUG(3,("Couldn't find domain %s: %s!\n",
			 ldb_dn_get_linearized(domain_dn),
			 ldb_errstring(sam_ctx)));
	} else {
		DEBUG(3,("error finding domain %s: %s!\n",
			 ldb_dn_get_linearized(domain_dn),
			 ldb_errstring(sam_ctx)));
	}

	for (i = 1; i < MIN(history_len, 3); i++) {
		struct samr_Password zero_string_hash;
		struct samr_Password zero_string_des_hash;
		struct samr_Password *nt_history_pwd = NULL;
		struct samr_Password *lm_history_pwd = NULL;
		NTTIME pwdLastSet;
		struct timeval tv_now;
		NTTIME now;
		int allowed_period_mins;
		NTTIME allowed_period;

		nt_status = samdb_result_passwords_from_history(tmp_ctx,
							auth_context->lp_ctx,
							msg, i,
							&lm_history_pwd,
							&nt_history_pwd);
		if (!NT_STATUS_IS_OK(nt_status)) {
			/*
			 * If we don't find element 'i' we won't find
			 * 'i+1' ...
			 */
			break;
		}

		/*
		 * We choose to avoid any issues
		 * around different LM and NT history
		 * lengths by only checking the NT
		 * history
		 */
		if (nt_history_pwd == NULL) {
			/*
			 * If we don't find element 'i' we won't find
			 * 'i+1' ...
			 */
			break;
		}

		/* Skip over all-zero hashes in the history */
		if (all_zero(nt_history_pwd->hash,
			     sizeof(nt_history_pwd->hash))) {
			continue;
		}

		/*
		 * This looks odd, but the password_hash module writes this in if
		 * (somehow) we didn't have an old NT hash
		 */

		E_md4hash("", zero_string_hash.hash);
		if (memcmp(nt_history_pwd->hash, zero_string_hash.hash, 16) == 0) {
			continue;
		}

		E_deshash("", zero_string_des_hash.hash);
		if (!lm_history_pwd || memcmp(lm_history_pwd->hash, zero_string_des_hash.hash, 16) == 0) {
			lm_history_pwd = NULL;
		}

		auth_status = authsam_password_ok(auth_context, tmp_ctx,
						  acct_flags,
						  lm_history_pwd,
						  nt_history_pwd,
						  user_info,
						  user_sess_key,
						  lm_sess_key);
		if (!NT_STATUS_IS_OK(auth_status)) {
			/*
			 * If this was not a correct password, try the next
			 * one from the history
			 */
			*user_sess_key = data_blob_null;
			*lm_sess_key = data_blob_null;
			continue;
		}

		if (i != 1) {
			/*
			 * The authentication was OK, but not against
			 * the previous password, which is stored at index 1.
			 *
			 * We just return the original wrong password.
			 * This skips the update of the bad pwd count,
			 * because this is almost certainly user error
			 * (or automatic login on a computer using a cached
			 * password from before the password change),
			 * not an attack.
			 */
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_WRONG_PASSWORD;
		}

		if (user_info->password_state != AUTH_PASSWORD_RESPONSE) {
			/*
			 * The authentication was OK against the previous password,
			 * but it's not a NTLM network authentication.
			 *
			 * We just return the original wrong password.
			 * This skips the update of the bad pwd count,
			 * because this is almost certainly user error
			 * (or automatic login on a computer using a cached
			 * password from before the password change),
			 * not an attack.
			 */
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_WRONG_PASSWORD;
		}

		/*
		 * If the password was OK, it's a NTLM network authentication
		 * and it was the previous password.
		 *
		 * Now we see if it is within the grace period,
		 * so that we don't break cached sessions on other computers
		 * before the user can lock and unlock their other screens
		 * (resetting their cached password).
		 *
		 * See http://support.microsoft.com/kb/906305
		 * OldPasswordAllowedPeriod ("old password allowed period")
		 * is specified in minutes. The default is 60.
		 */
		allowed_period_mins = lpcfg_old_password_allowed_period(auth_context->lp_ctx);
		/*
		 * NTTIME uses 100ns units
		 */
		allowed_period = allowed_period_mins * 60 * 1000*1000*10;
		pwdLastSet = samdb_result_nttime(msg, "pwdLastSet", 0);
		tv_now = timeval_current();
		now = timeval_to_nttime(&tv_now);

		if (now < pwdLastSet) {
			/*
			 * time jump?
			 *
			 * We just return the original wrong password.
			 * This skips the update of the bad pwd count,
			 * because this is almost certainly user error
			 * (or automatic login on a computer using a cached
			 * password from before the password change),
			 * not an attack.
			 */
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_WRONG_PASSWORD;
		}

		if ((now - pwdLastSet) >= allowed_period) {
			/*
			 * The allowed period is over.
			 *
			 * We just return the original wrong password.
			 * This skips the update of the bad pwd count,
			 * because this is almost certainly user error
			 * (or automatic login on a computer using a cached
			 * password from before the password change),
			 * not an attack.
			 */
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_WRONG_PASSWORD;
		}

		/*
		 * We finally allow the authentication with the
		 * previous password within the allowed period.
		 */
		if (user_sess_key->data) {
			talloc_steal(mem_ctx, user_sess_key->data);
		}
		if (lm_sess_key->data) {
			talloc_steal(mem_ctx, lm_sess_key->data);
		}

		TALLOC_FREE(tmp_ctx);
		return auth_status;
	}

	/*
	 * If we are not in the allowed period or match an old password,
	 * we didn't return early. Now update the badPwdCount et al.
	 */
	nt_status = authsam_update_bad_pwd_count(auth_context->sam_ctx,
						 msg, domain_dn);
	if (!NT_STATUS_IS_OK(nt_status)) {
		/*
		 * We need to return the original
		 * NT_STATUS_WRONG_PASSWORD error, so there isn't
		 * anything more we can do than write something into
		 * the log
		 */
		DEBUG(0, ("Failed to note bad password for user [%s]: %s\n",
			  user_info->mapped.account_name,
			  nt_errstr(nt_status)));
	}

	if (samdb_rodc(auth_context->sam_ctx, &am_rodc) == LDB_SUCCESS && am_rodc) {
		*authoritative = false;
	}

	TALLOC_FREE(tmp_ctx);
	return NT_STATUS_WRONG_PASSWORD;
}
Example #7
0
/* Calculate the NTLMv2 response for the given challenge, using the
   specified authentication identity (username and domain), password 
   and client nonce.
  
   challenge: Identity \0 Challenge Size \0 Server Challenge + Client Challenge
*/
static void netntlmv2_crypt_all(int count)
{
  HMACMD5Context ctx;
  unsigned char ntlm[16];
  unsigned char ntlm_v2_hash[16];
  uchar *identity = NULL;
  int identity_length = 0;
  int16 identity_usc[129];
  int identity_usc_length = 0;
  int challenge_size = 0; 

  memset(ntlm, 0, 16);
  memset(ntlm_v2_hash, 0, 16);
  memset(output, 0, 16);
  memset(identity_usc, 0, 129);
  identity_usc_length = 0;

  /* --- HMAC #1 Caculations --- */

  /* Convert identity (username + domain) string to NT unicode */
  identity_length = strlen((char *)challenge);
  identity = challenge;

  ntlmv2_mbstowcs(identity_usc, identity, identity_length);
  identity_usc_length = ntlmv2_wcslen(identity_usc) * sizeof(int16);

  /* Generate 16-byte NTLM hash */
  E_md4hash(saved_plain, ntlm);

  /* Generate 16-byte NTLMv2 Hash */
  /* HMAC-MD5(Username + Domain, NTLM Hash) */
  hmac_md5_init_limK_to_64(ntlm, 16, &ctx);
  hmac_md5_update((const unsigned char *)identity_usc, identity_usc_length, &ctx);
  hmac_md5_final(ntlm_v2_hash, &ctx);

  /* --- Blob Construction --- */

  /*  
    The blob consists of the target (from Type 2 message), client nonce and timestamp. 
    This data was provided by the client during authentication and we can use it as is. 
  */

  /* --- HMAC #2 Caculations --- */

  /*
    The (server) challenge from the Type 2 message is concatenated with the blob. The 
    HMAC-MD5 message authentication code algorithm is applied to this value using the 
    16-byte NTLMv2 hash (calculated above) as the key. This results in a 16-byte output 
    value.
  */

  /* 
    Generate 16-byte non-client nonce portion of NTLMv2 Response 
    HMAC-MD5(Challenge + Nonce, NTLMv2 Hash)
  
    The length of the challenge was set in netntlmv2_get_salt(). We find the server
    challenge and blob following the identity and challenge size value.
    challenge -> Identity \0 Size (2 bytes) \0 Server Challenge + Client Challenge (Blob)
  */
  challenge_size = (*(challenge + identity_length + 1) << 8) | *(challenge + identity_length + 2);

  hmac_md5_init_limK_to_64(ntlm_v2_hash, 16, &ctx);
  hmac_md5_update(challenge + identity_length + 1 + 2 + 1, challenge_size, &ctx); 
  hmac_md5_final(output, &ctx);
}
Example #8
0
static bool test_lm_ntlm_broken(enum ntlm_break break_which) 
{
	bool pass = True;
	NTSTATUS nt_status;
	uint32 flags = 0;
	DATA_BLOB lm_response = data_blob(NULL, 24);
	DATA_BLOB nt_response = data_blob(NULL, 24);
	DATA_BLOB session_key = data_blob(NULL, 16);

	uchar lm_key[8];
	uchar user_session_key[16];
	uchar lm_hash[16];
	uchar nt_hash[16];
	DATA_BLOB chall = get_challenge();
	char *error_string;
	
	ZERO_STRUCT(lm_key);
	ZERO_STRUCT(user_session_key);

	flags |= WBFLAG_PAM_LMKEY;
	flags |= WBFLAG_PAM_USER_SESSION_KEY;

	SMBencrypt(opt_password,chall.data,lm_response.data);
	E_deshash(opt_password, lm_hash); 

	SMBNTencrypt(opt_password,chall.data,nt_response.data);

	E_md4hash(opt_password, nt_hash);
	SMBsesskeygen_ntv1(nt_hash, session_key.data);

	switch (break_which) {
	case BREAK_NONE:
		break;
	case BREAK_LM:
		lm_response.data[0]++;
		break;
	case BREAK_NT:
		nt_response.data[0]++;
		break;
	case NO_LM:
		data_blob_free(&lm_response);
		break;
	case NO_NT:
		data_blob_free(&nt_response);
		break;
	}

	nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
					      opt_workstation,
					      &chall,
					      &lm_response,
					      &nt_response,
					      flags,
					      lm_key, 
					      user_session_key,
					      &error_string, NULL);
	
	data_blob_free(&lm_response);

	if (!NT_STATUS_IS_OK(nt_status)) {
		d_printf("%s (0x%x)\n", 
			 error_string,
			 NT_STATUS_V(nt_status));
		SAFE_FREE(error_string);
		return break_which == BREAK_NT;
	}

	if (memcmp(lm_hash, lm_key, 
		   sizeof(lm_key)) != 0) {
		DEBUG(1, ("LM Key does not match expectations!\n"));
 		DEBUG(1, ("lm_key:\n"));
		dump_data(1, lm_key, 8);
		DEBUG(1, ("expected:\n"));
		dump_data(1, lm_hash, 8);
		pass = False;
	}

	if (break_which == NO_NT) {
		if (memcmp(lm_hash, user_session_key, 
			   8) != 0) {
			DEBUG(1, ("NT Session Key does not match expectations (should be LM hash)!\n"));
			DEBUG(1, ("user_session_key:\n"));
			dump_data(1, user_session_key, sizeof(user_session_key));
			DEBUG(1, ("expected:\n"));
			dump_data(1, lm_hash, sizeof(lm_hash));
			pass = False;
		}
	} else {		
		if (memcmp(session_key.data, user_session_key, 
			   sizeof(user_session_key)) != 0) {
			DEBUG(1, ("NT Session Key does not match expectations!\n"));
			DEBUG(1, ("user_session_key:\n"));
			dump_data(1, user_session_key, 16);
			DEBUG(1, ("expected:\n"));
			dump_data(1, session_key.data, session_key.length);
			pass = False;
		}
	}
        return pass;
}
Example #9
0
bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext)
{
	uchar new_lanman_p16[LM_HASH_LEN];
	uchar new_nt_p16[NT_HASH_LEN];
	uchar *pwhistory;
	uint32 pwHistLen;
	uint32 current_history_len;

	if (!plaintext)
		return False;

	/* Calculate the MD4 hash (NT compatible) of the password */
	E_md4hash(plaintext, new_nt_p16);

	if (!pdb_set_nt_passwd (sampass, new_nt_p16, PDB_CHANGED)) 
		return False;

	if (!E_deshash(plaintext, new_lanman_p16)) {
		/* E_deshash returns false for 'long' passwords (> 14
		   DOS chars).  This allows us to match Win2k, which
		   does not store a LM hash for these passwords (which
		   would reduce the effective password length to 14 */

		if (!pdb_set_lanman_passwd (sampass, NULL, PDB_CHANGED)) 
			return False;
	} else {
		if (!pdb_set_lanman_passwd (sampass, new_lanman_p16, PDB_CHANGED)) 
			return False;
	}

	if (!pdb_set_plaintext_pw_only (sampass, plaintext, PDB_CHANGED)) 
		return False;

	if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED))
		return False;

	if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) == 0) {
		/*
		 * No password history for non-user accounts
		 */
		return true;
	}

	pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen);

	if (pwHistLen == 0) {
		/* Set the history length to zero. */
		pdb_set_pw_history(sampass, NULL, 0, PDB_CHANGED);
		return true;
	}

	/*
	 * We need to make sure we don't have a race condition here -
	 * the account policy history length can change between when
	 * the pw_history was first loaded into the struct samu struct
	 * and now.... JRA.
	 */
	pwhistory = (uchar *)pdb_get_pw_history(sampass, &current_history_len);

	if ((current_history_len != 0) && (pwhistory == NULL)) {
		DEBUG(1, ("pdb_set_plaintext_passwd: pwhistory == NULL!\n"));
		return false;
	}

	if (current_history_len < pwHistLen) {
		/*
		 * Ensure we have space for the needed history. This
		 * also takes care of an account which did not have
		 * any history at all so far, i.e. pwhistory==NULL
		 */
		uchar *new_history = talloc_zero_array(
			sampass, uchar,
			pwHistLen*PW_HISTORY_ENTRY_LEN);

		if (!new_history) {
			return False;
		}

		memcpy(new_history, pwhistory,
		       current_history_len*PW_HISTORY_ENTRY_LEN);

		pwhistory = new_history;
	}

	/*
	 * Make room for the new password in the history list.
	 */
	if (pwHistLen > 1) {
		memmove(&pwhistory[PW_HISTORY_ENTRY_LEN], pwhistory,
			(pwHistLen-1)*PW_HISTORY_ENTRY_LEN );
	}

	/*
	 * Fill the salt area with 0-s: this indicates that
	 * a plain nt hash is stored in the has area.
	 * The old format was to store a 16 byte salt and
	 * then an md5hash of the nt_hash concatenated with
	 * the salt.
	 */
	memset(pwhistory, 0, PW_HISTORY_SALT_LEN);

	/*
	 * Store the plain nt hash in the second 16 bytes.
	 * The old format was to store the md5 hash of
	 * the salt+newpw.
	 */
	memcpy(&pwhistory[PW_HISTORY_SALT_LEN], new_nt_p16, SALTED_MD5_HASH_LEN);

	pdb_set_pw_history(sampass, pwhistory, pwHistLen, PDB_CHANGED);

	return True;
}
Example #10
0
static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, 
					 const DATA_BLOB reply, DATA_BLOB *next_request) 
{
	uint32 chal_flags, ntlmssp_command, unkn1, unkn2;
	DATA_BLOB server_domain_blob;
	DATA_BLOB challenge_blob;
	DATA_BLOB struct_blob = data_blob(NULL, 0);
	char *server_domain;
	const char *chal_parse_string;
	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 encrypted_session_key = data_blob(NULL, 0);
	NTSTATUS nt_status;

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

		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, lp_client_lanman_auth());

	if (ntlmssp_state->unicode) {
		if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
			chal_parse_string = "CdUdbddB";
		} else {
			chal_parse_string = "CdUdbdd";
		}
		auth_gen_string = "CdBBUUUBd";
	} else {
		if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
			chal_parse_string = "CdAdbddB";
		} else {
			chal_parse_string = "CdAdbdd";
		}

		auth_gen_string = "CdBBAAABd";
	}

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

	if (!msrpc_parse(&reply, chal_parse_string,
			 "NTLMSSP",
			 &ntlmssp_command, 
			 &server_domain,
			 &chal_flags,
			 &challenge_blob, 8,
			 &unkn1, &unkn2,
			 &struct_blob)) {
		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));
		dump_data(2, (const char *)reply.data, reply.length);
		return NT_STATUS_INVALID_PARAMETER;
	}

	ntlmssp_state->server_domain = talloc_strdup(ntlmssp_state->mem_ctx,
						     server_domain);

	SAFE_FREE(server_domain);
	if (challenge_blob.length != 8) {
		data_blob_free(&struct_blob);
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!ntlmssp_state->password) {
		static const uchar zeros[16];
		/* do nothing - blobs are zero length */

		/* session key is all zeros */
		session_key = data_blob_talloc(ntlmssp_state->mem_ctx, zeros, 16);
		
		/* not doing NLTM2 without a password */
		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
	} else if (ntlmssp_state->use_ntlmv2) {

		if (!struct_blob.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(ntlmssp_state->user, 
				      ntlmssp_state->domain, 
				      ntlmssp_state->password, &challenge_blob, 
				      &struct_blob, 
				      &lm_response, &nt_response, &session_key)) {
			data_blob_free(&challenge_blob);
			data_blob_free(&struct_blob);
			return NT_STATUS_NO_MEMORY;
		}
	} else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
		struct MD5Context md5_session_nonce_ctx;
		uchar nt_hash[16];
		uchar session_nonce[16];
		uchar session_nonce_hash[16];
		uchar user_session_key[16];
		E_md4hash(ntlmssp_state->password, nt_hash);
		
		lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
		generate_random_buffer(lm_response.data, 8);
		memset(lm_response.data+8, 0, 16);

		memcpy(session_nonce, challenge_blob.data, 8);
		memcpy(&session_nonce[8], lm_response.data, 8);
	
		MD5Init(&md5_session_nonce_ctx);
		MD5Update(&md5_session_nonce_ctx, challenge_blob.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, (const char *)session_nonce_hash, 8);
		
		nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
		SMBNTencrypt(ntlmssp_state->password,
			     session_nonce_hash,
			     nt_response.data);

		session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);

		SMBsesskeygen_ntv1(nt_hash, NULL, 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);
	} else {
		
		
		uchar lm_hash[16];
		uchar nt_hash[16];
		E_deshash(ntlmssp_state->password, lm_hash);
		E_md4hash(ntlmssp_state->password, nt_hash);
		
		/* lanman auth is insecure, it may be disabled */
		if (lp_client_lanman_auth()) {
			lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
			SMBencrypt(ntlmssp_state->password,challenge_blob.data,
				   lm_response.data);
		}
		
		nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
		SMBNTencrypt(ntlmssp_state->password,challenge_blob.data,
			     nt_response.data);
		
		session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
		if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) 
		    && lp_client_lanman_auth()) {
			SMBsesskeygen_lmv1(lm_hash, lm_response.data, 
					   session_key.data);
			dump_data_pw("LM session key\n", session_key.data, session_key.length);
		} else {
			SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
			dump_data_pw("NT session key:\n", session_key.data, session_key.length);
		}
	}
	data_blob_free(&struct_blob);

	/* 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 client_session_key[16];
		generate_random_buffer(client_session_key, sizeof(client_session_key));

		/* Encrypt the new session key with the old one */
		encrypted_session_key = data_blob(client_session_key, sizeof(client_session_key));
		dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length);
		SamOEMhash(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 */
		data_blob_free(&session_key);
		session_key = data_blob_talloc(ntlmssp_state->mem_ctx, client_session_key, sizeof(client_session_key));
	}

	/* this generates the actual auth packet */
	if (!msrpc_gen(next_request, auth_gen_string, 
		       "NTLMSSP", 
		       NTLMSSP_AUTH, 
		       lm_response.data, lm_response.length,
		       nt_response.data, nt_response.length,
		       ntlmssp_state->domain, 
		       ntlmssp_state->user, 
		       ntlmssp_state->get_global_myname(), 
		       encrypted_session_key.data, encrypted_session_key.length,
		       ntlmssp_state->neg_flags)) {
		
		return NT_STATUS_NO_MEMORY;
	}

	data_blob_free(&encrypted_session_key);

	data_blob_free(&ntlmssp_state->chal);

	ntlmssp_state->chal = challenge_blob;
	ntlmssp_state->lm_resp = lm_response;
	ntlmssp_state->nt_resp = nt_response;
	ntlmssp_state->session_key = session_key;

	ntlmssp_state->expected_state = NTLMSSP_UNKNOWN;

	if (!NT_STATUS_IS_OK(nt_status = ntlmssp_sign_init(ntlmssp_state))) {
		DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", nt_errstr(nt_status)));
		return nt_status;
	}

	return NT_STATUS_MORE_PROCESSING_REQUIRED;
}
Example #11
0
NTSTATUS netdom_join_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli, 
                           DOM_SID *dom_sid, const char *clear_pw,
                           enum netdom_domain_t dom_type )
{	
	struct rpc_pipe_client *pipe_hnd = NULL;
	POLICY_HND sam_pol, domain_pol, user_pol;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	char *acct_name;
	const char *const_acct_name;
	uint32 user_rid;
	uint32 num_rids, *name_types, *user_rids;
	uint32 flags = 0x3e8;
	uint32 acb_info = ACB_WSTRUST;
	uint32 acct_flags=0;
	uint32 fields_present;
	uchar pwbuf[532];
	SAM_USERINFO_CTR ctr;
	SAM_USER_INFO_25 p25;
	const int infolevel = 25;
	struct MD5Context md5ctx;
	uchar md5buffer[16];
	DATA_BLOB digested_session_key;
	uchar md4_trust_password[16];

	/* Open the domain */
	
	if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
		DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
			nt_errstr(status) ));
		return status;
	}

	status = rpccli_samr_connect(pipe_hnd, mem_ctx, 
			SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
	if ( !NT_STATUS_IS_OK(status) )
		return status;

	
	status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
			SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
	if ( !NT_STATUS_IS_OK(status) )
		return status;

	/* Create domain user */
	
	acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); 
	strlower_m(acct_name);
	const_acct_name = acct_name;

	/* Don't try to set any acb_info flags other than ACB_WSTRUST */

        acct_flags = SAMR_GENERIC_READ | SAMR_GENERIC_WRITE |
                SAMR_GENERIC_EXECUTE | SAMR_STANDARD_WRITEDAC |
                SAMR_STANDARD_DELETE | SAMR_USER_SETPASS | SAMR_USER_GETATTR |
                SAMR_USER_SETATTR;
	DEBUG(10, ("Creating account with flags: %d\n",acct_flags));
	status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
			acct_name, acb_info, acct_flags, &user_pol, &user_rid);

	if ( !NT_STATUS_IS_OK(status) 
		&& !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) 
	{
		d_fprintf(stderr, "Creation of workstation account failed\n");

		/* If NT_STATUS_ACCESS_DENIED then we have a valid
		   username/password combo but the user does not have
		   administrator access. */

		if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
			d_fprintf(stderr, "User specified does not have administrator privileges\n");

		return status;
	}

	/* We *must* do this.... don't ask... */

	if (NT_STATUS_IS_OK(status)) {
		rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
	}

	status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
			&domain_pol, flags, 1, &const_acct_name, 
			&num_rids, &user_rids, &name_types);
	if ( !NT_STATUS_IS_OK(status) )
		return status;

	if ( name_types[0] != SID_NAME_USER) {
		DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
		return NT_STATUS_INVALID_WORKSTATION;
	}

	user_rid = user_rids[0];
		
	/* Open handle on user */

	status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
			SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}
	
	/* Create a random machine account password and generate the hash */

	E_md4hash(clear_pw, md4_trust_password);
	encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
	
	generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer));
	digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
	
	MD5Init(&md5ctx);
	MD5Update(&md5ctx, md5buffer, sizeof(md5buffer));
	MD5Update(&md5ctx, cli->user_session_key.data, cli->user_session_key.length);
	MD5Final(digested_session_key.data, &md5ctx);
	
	SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
	memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));

	/* Fill in the additional account flags now */

	acb_info |= ACB_PWNOEXP;
	if ( dom_type == ND_TYPE_AD ) {
#if !defined(ENCTYPE_ARCFOUR_HMAC)
		acb_info |= ACB_USE_DES_KEY_ONLY;
#endif
		;;
	}

	/* Set password and account flags on machine account */

	ZERO_STRUCT(ctr);
	ZERO_STRUCT(p25);

	fields_present = ACCT_NT_PWD_SET | ACCT_LM_PWD_SET | ACCT_FLAGS;
	init_sam_user_info25P(&p25, fields_present, acb_info, (char *)pwbuf);

	ctr.switch_value = infolevel;
	ctr.info.id25    = &p25;

	status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol,
					   infolevel, &cli->user_session_key, &ctr);

	if ( !NT_STATUS_IS_OK(status) ) {
		d_fprintf( stderr, "Failed to set password for machine account (%s)\n", 
			nt_errstr(status));
		return status;
	}

	rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
	cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
	
	return status;
}
/* Calculate the NTLMv2 response for the given challenge, using the
   specified authentication identity (username and domain), password
   and client nonce.

   challenge: Identity length, Identity\0, Challenge Size, Server Challenge + Client Challenge
*/
static int crypt_all(int *pcount, struct db_salt *salt)
{
	int count = *pcount;
	int identity_length, challenge_size;
	int i = 0;

	/* --- HMAC #1 Calculations --- */
	identity_length = challenge[0];
	challenge_size = (*(challenge + 1 + identity_length + 1) << 8) | *(challenge + 1 + identity_length + 2);

#ifdef _OPENMP
#pragma omp parallel for
	for(i=0; i<count; i++)
#endif
	{
		unsigned char ntlm_v2_hash[16];
		HMACMD5Context ctx;

		if (!keys_prepared) {
			unsigned char ntlm[16];
			int len;

			/* Generate 16-byte NTLM hash */
			len = E_md4hash(saved_plain[i], saved_len[i], ntlm);

			// We do key setup of the next HMAC_MD5 here (once per salt)
			hmac_md5_init_K16(ntlm, &saved_ctx[i]);

			if (len <= 0)
				saved_plain[i][-len] = 0; // match truncation
		}

		/* HMAC-MD5(Username + Domain, NTLM Hash) */
		memcpy(&ctx, &saved_ctx[i], sizeof(ctx));
		hmac_md5_update((unsigned char *)&challenge[1], identity_length, &ctx);
		hmac_md5_final(ntlm_v2_hash, &ctx);

		/* --- Blob Construction --- */

		/*
		    The blob consists of the target (from Type 2 message), client nonce and timestamp.
		    This data was provided by the client during authentication and we can use it as is.
		*/

		/* --- HMAC #2 Caculations --- */

		/*
		  The (server) challenge from the Type 2 message is concatenated with the blob. The
		  HMAC-MD5 message authentication code algorithm is applied to this value using the
		  16-byte NTLMv2 hash (calculated above) as the key. This results in a 16-byte output
		  value.
		*/

		/*
		   Generate 16-byte non-client nonce portion of NTLMv2 Response
		   HMAC-MD5(Challenge + Nonce, NTLMv2 Hash)

		   The length of the challenge was set in get_salt(). We find the server
		   challenge and blob following the identity and challenge size value.
		   challenge -> Identity length, Identity\0, Size (2 bytes), Server Challenge + Client Challenge (Blob)
		*/
		hmac_md5(ntlm_v2_hash, challenge + 1 + identity_length + 1 + 2, challenge_size, (unsigned char*)output[i]);
	}
	keys_prepared = 1;

	return count;
}
Example #13
0
bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext)
{
	uchar new_lanman_p16[LM_HASH_LEN];
	uchar new_nt_p16[NT_HASH_LEN];

	if (!plaintext)
		return False;

	/* Calculate the MD4 hash (NT compatible) of the password */
	E_md4hash(plaintext, new_nt_p16);

	if (!pdb_set_nt_passwd (sampass, new_nt_p16, PDB_CHANGED)) 
		return False;

	if (!E_deshash(plaintext, new_lanman_p16)) {
		/* E_deshash returns false for 'long' passwords (> 14
		   DOS chars).  This allows us to match Win2k, which
		   does not store a LM hash for these passwords (which
		   would reduce the effective password length to 14 */

		if (!pdb_set_lanman_passwd (sampass, NULL, PDB_CHANGED)) 
			return False;
	} else {
		if (!pdb_set_lanman_passwd (sampass, new_lanman_p16, PDB_CHANGED)) 
			return False;
	}

	if (!pdb_set_plaintext_pw_only (sampass, plaintext, PDB_CHANGED)) 
		return False;

	if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED))
		return False;

	/* Store the password history. */
	if (pdb_get_acct_ctrl(sampass) & ACB_NORMAL) {
		uchar *pwhistory;
		uint32 pwHistLen;
		pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen);
		if (pwHistLen != 0){
			uint32 current_history_len;
			/* We need to make sure we don't have a race condition here - the
			   account policy history length can change between when the pw_history
			   was first loaded into the struct samu struct and now.... JRA. */
			pwhistory = (uchar *)pdb_get_pw_history(sampass, &current_history_len);

			if (current_history_len != pwHistLen) {
				/* After closing and reopening struct samu the history
					values will sync up. We can't do this here. */

				/* current_history_len > pwHistLen is not a problem - we
					have more history than we need. */

				if (current_history_len < pwHistLen) {
					/* Ensure we have space for the needed history. */
					uchar *new_history = (uchar *)TALLOC(sampass,
								pwHistLen*PW_HISTORY_ENTRY_LEN);
					if (!new_history) {
						return False;
					}

					/* And copy it into the new buffer. */
					if (current_history_len) {
						memcpy(new_history, pwhistory,
							current_history_len*PW_HISTORY_ENTRY_LEN);
					}
					/* Clearing out any extra space. */
					memset(&new_history[current_history_len*PW_HISTORY_ENTRY_LEN],
						'\0', (pwHistLen-current_history_len)*PW_HISTORY_ENTRY_LEN);
					/* Finally replace it. */
					pwhistory = new_history;
				}
			}
			if (pwhistory && pwHistLen){
				/* Make room for the new password in the history list. */
				if (pwHistLen > 1) {
					memmove(&pwhistory[PW_HISTORY_ENTRY_LEN],
						pwhistory, (pwHistLen -1)*PW_HISTORY_ENTRY_LEN );
				}
				/* Create the new salt as the first part of the history entry. */
				generate_random_buffer(pwhistory, PW_HISTORY_SALT_LEN);

				/* Generate the md5 hash of the salt+new password as the second
					part of the history entry. */

				E_md5hash(pwhistory, new_nt_p16, &pwhistory[PW_HISTORY_SALT_LEN]);
				pdb_set_pw_history(sampass, pwhistory, pwHistLen, PDB_CHANGED);
			} else {
				DEBUG (10,("pdb_get_set.c: pdb_set_plaintext_passwd: pwhistory was NULL!\n"));
			}
		} else {
			/* Set the history length to zero. */
			pdb_set_pw_history(sampass, NULL, 0, PDB_CHANGED);
		}
	}

	return True;
}
Example #14
0
void SMBNTencrypt(const char *passwd, uchar *c8, uchar *p24)
{
	uchar nt_hash[16];
	E_md4hash(passwd, nt_hash);    
	SMBNTencrypt_hash(nt_hash, c8, p24);
}
Example #15
0
static int crypt_all(int *pcount, struct db_salt *salt)
{
	int count = *pcount;
	int i;
	size_t *lws = local_work_size ? &local_work_size : NULL;

	/* Don't do more than requested */
	global_work_size = local_work_size ? (count + local_work_size - 1) / local_work_size * local_work_size : count;

	/* Self-test cludge */
	if (idx_offset > 4 * (global_work_size + 1))
		idx_offset = 0;

	if (new_keys) {
		if (key_idx > key_offset)
			HANDLE_CLERROR(clEnqueueWriteBuffer(queue[gpu_id], cl_saved_key, CL_FALSE, key_offset, key_idx - key_offset, saved_key + key_offset, 0, NULL, NULL), "Failed transferring keys");
		HANDLE_CLERROR(clEnqueueWriteBuffer(queue[gpu_id], cl_saved_idx, CL_FALSE, idx_offset, 4 * (global_work_size + 1) - idx_offset, saved_idx + (idx_offset / 4), 0, NULL, multi_profilingEvent[0]), "Failed transferring index");
		HANDLE_CLERROR(clEnqueueNDRangeKernel(queue[gpu_id], krb5pa_md5_nthash, 1, NULL, &global_work_size, lws, 0, NULL, multi_profilingEvent[1]), "Failed running first kernel");

		new_keys = 0;
	}
	HANDLE_CLERROR(clEnqueueNDRangeKernel(queue[gpu_id], crypt_kernel, 1, NULL, &global_work_size, lws, 0, NULL, multi_profilingEvent[2]), "Failed running second kernel");
	HANDLE_CLERROR(clEnqueueReadBuffer(queue[gpu_id], cl_result, CL_TRUE, 0, BINARY_SIZE * global_work_size, output, 0, NULL, multi_profilingEvent[3]), "failed reading results back");

	for (i = 0; i < count; i++) {
		unsigned char *binary = &((unsigned char*)output)[BINARY_SIZE * i];

		// Check for known plaintext
		if (binary[14] == '2' && binary[15] == '0') {
			salt_t *salt = (salt_t*)saltblob;
			unsigned char K[KEY_SIZE];
			unsigned char K1[KEY_SIZE];
			unsigned char K3[KEY_SIZE];
			unsigned char plaintext[TIMESTAMP_SIZE];
			const unsigned char one[] = { 1, 0, 0, 0 };
			char *password;

			// K = MD4(UTF-16LE(password))
			// This is not thread safe
			password = get_key(i);
			E_md4hash((unsigned char*)password,
			    strlen(password), K);

			// K1 = HMAC-MD5(K, 1)
			// 1 is encoded as little endian in 4 bytes (0x01000000)
			hmac_md5(K, (unsigned char*)&one, 4, K1);

			// K3 = HMAC-MD5(K1, CHECKSUM)
			hmac_md5(K1, (unsigned char*)salt->checksum,
			         CHECKSUM_SIZE, K3);

			// Decrypt the timestamp
			RC4_single(K3, KEY_SIZE, salt->timestamp,
			           TIMESTAMP_SIZE, plaintext);

			if (plaintext[28] == 'Z') {
				// create checksum K2 = HMAC-MD5(K1, plaintext)
				hmac_md5(K1, plaintext, TIMESTAMP_SIZE, binary);
			}
		}
	}

	return count;
}
Example #16
0
static bool test_ntlm_in_both(void) 
{
	bool pass = True;
	NTSTATUS nt_status;
	uint32 flags = 0;
	DATA_BLOB nt_response = data_blob(NULL, 24);
	DATA_BLOB session_key = data_blob(NULL, 16);

	uint8 lm_key[8];
	uint8 lm_hash[16];
	uint8 user_session_key[16];
	uint8 nt_hash[16];
	DATA_BLOB chall = get_challenge();
	char *error_string;
	
	ZERO_STRUCT(lm_key);
	ZERO_STRUCT(user_session_key);

	flags |= WBFLAG_PAM_LMKEY;
	flags |= WBFLAG_PAM_USER_SESSION_KEY;

	SMBNTencrypt(opt_password,chall.data,nt_response.data);
	E_md4hash(opt_password, nt_hash);
	SMBsesskeygen_ntv1(nt_hash, session_key.data);

	E_deshash(opt_password, lm_hash); 

	nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
					      opt_workstation,
					      &chall,
					      &nt_response,
					      &nt_response,
					      flags,
					      lm_key,
					      user_session_key,
					      &error_string, NULL);
	
	data_blob_free(&nt_response);

	if (!NT_STATUS_IS_OK(nt_status)) {
		d_printf("%s (0x%x)\n", 
			 error_string,
			 NT_STATUS_V(nt_status));
		SAFE_FREE(error_string);
		return False;
	}

	if (memcmp(lm_hash, lm_key, 
		   sizeof(lm_key)) != 0) {
		DEBUG(1, ("LM Key does not match expectations!\n"));
 		DEBUG(1, ("lm_key:\n"));
		dump_data(1, lm_key, 8);
		DEBUG(1, ("expected:\n"));
		dump_data(1, lm_hash, 8);
		pass = False;
	}
	if (memcmp(session_key.data, user_session_key, 
		   sizeof(user_session_key)) != 0) {
		DEBUG(1, ("NT Session Key does not match expectations!\n"));
 		DEBUG(1, ("user_session_key:\n"));
		dump_data(1, user_session_key, 16);
 		DEBUG(1, ("expected:\n"));
		dump_data(1, session_key.data, session_key.length);
		pass = False;
	}


        return pass;
}
Example #17
0
int net_rpc_join_newstyle(int argc, const char **argv) 
{

	/* libsmb variables */

	struct cli_state *cli;
	TALLOC_CTX *mem_ctx;
        uint32 acb_info = ACB_WSTRUST;
	uint32 sec_channel_type;

	/* rpc variables */

	POLICY_HND lsa_pol, sam_pol, domain_pol, user_pol;
	DOM_SID *domain_sid;
	uint32 user_rid;

	/* Password stuff */

	char *clear_trust_password = NULL;
	uchar pwbuf[516];
	SAM_USERINFO_CTR ctr;
	SAM_USER_INFO_24 p24;
	SAM_USER_INFO_10 p10;
	uchar md4_trust_password[16];

	/* Misc */

	NTSTATUS result;
	int retval = 1;
	char *domain;
	uint32 num_rids, *name_types, *user_rids;
	uint32 flags = 0x3e8;
	char *acct_name;
	const char *const_acct_name;

	/* check what type of join */
	if (argc >= 0) {
		sec_channel_type = get_sec_channel_type(argv[0]);
	} else {
		sec_channel_type = get_sec_channel_type(NULL);
	}

	switch (sec_channel_type) {
	case SEC_CHAN_WKSTA:
		acb_info = ACB_WSTRUST;
		break;
	case SEC_CHAN_BDC:
		acb_info = ACB_SVRTRUST;
		break;
#if 0
	case SEC_CHAN_DOMAIN:
		acb_info = ACB_DOMTRUST;
		break;
#endif
	}

	/* Connect to remote machine */

	if (!(cli = net_make_ipc_connection(NET_FLAGS_PDC))) 
		return 1;

	if (!(mem_ctx = talloc_init("net_rpc_join_newstyle"))) {
		DEBUG(0, ("Could not initialise talloc context\n"));
		goto done;
	}

	/* Fetch domain sid */

	if (!cli_nt_session_open(cli, PI_LSARPC)) {
		DEBUG(0, ("Error connecting to LSA pipe\n"));
		goto done;
	}


	CHECK_RPC_ERR(cli_lsa_open_policy(cli, mem_ctx, True,
					  SEC_RIGHTS_MAXIMUM_ALLOWED,
					  &lsa_pol),
		      "error opening lsa policy handle");

	CHECK_RPC_ERR(cli_lsa_query_info_policy(cli, mem_ctx, &lsa_pol,
						5, &domain, &domain_sid),
		      "error querying info policy");

	cli_lsa_close(cli, mem_ctx, &lsa_pol);

	cli_nt_session_close(cli); /* Done with this pipe */

	/* Create domain user */
	if (!cli_nt_session_open(cli, PI_SAMR)) {
		DEBUG(0, ("Error connecting to SAM pipe\n"));
		goto done;
	}

	CHECK_RPC_ERR(cli_samr_connect(cli, mem_ctx, 
				       SEC_RIGHTS_MAXIMUM_ALLOWED,
				       &sam_pol),
		      "could not connect to SAM database");

	
	CHECK_RPC_ERR(cli_samr_open_domain(cli, mem_ctx, &sam_pol,
					   SEC_RIGHTS_MAXIMUM_ALLOWED,
					   domain_sid, &domain_pol),
		      "could not open domain");

	/* Create domain user */
	acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); 
	strlower_m(acct_name);
	const_acct_name = acct_name;

	result = cli_samr_create_dom_user(cli, mem_ctx, &domain_pol,
					  acct_name, acb_info,
					  0xe005000b, &user_pol, 
					  &user_rid);

	if (!NT_STATUS_IS_OK(result) && 
	    !NT_STATUS_EQUAL(result, NT_STATUS_USER_EXISTS)) {
		d_printf("Creation of workstation account failed\n");

		/* If NT_STATUS_ACCESS_DENIED then we have a valid
		   username/password combo but the user does not have
		   administrator access. */

		if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
			d_printf("User specified does not have administrator privileges\n");

		goto done;
	}

	/* We *must* do this.... don't ask... */

	if (NT_STATUS_IS_OK(result))
		cli_samr_close(cli, mem_ctx, &user_pol);

	CHECK_RPC_ERR_DEBUG(cli_samr_lookup_names(cli, mem_ctx,
						  &domain_pol, flags,
						  1, &const_acct_name, 
						  &num_rids,
						  &user_rids, &name_types),
			    ("error looking up rid for user %s: %s\n",
			     acct_name, nt_errstr(result)));

	if (name_types[0] != SID_NAME_USER) {
		DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
		goto done;
	}

	user_rid = user_rids[0];
		
	/* Open handle on user */

	CHECK_RPC_ERR_DEBUG(
		cli_samr_open_user(cli, mem_ctx, &domain_pol,
				   SEC_RIGHTS_MAXIMUM_ALLOWED,
				   user_rid, &user_pol),
		("could not re-open existing user %s: %s\n",
		 acct_name, nt_errstr(result)));
	
	/* Create a random machine account password */

	{ 
		char *str;
		str = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
		clear_trust_password = SMB_STRDUP(str);
		E_md4hash(clear_trust_password, md4_trust_password);
	}

	encode_pw_buffer(pwbuf, clear_trust_password, STR_UNICODE);

	/* Set password on machine account */

	ZERO_STRUCT(ctr);
	ZERO_STRUCT(p24);

	init_sam_user_info24(&p24, (char *)pwbuf,24);

	ctr.switch_value = 24;
	ctr.info.id24 = &p24;

	CHECK_RPC_ERR(cli_samr_set_userinfo(cli, mem_ctx, &user_pol, 24, 
					    &cli->user_session_key, &ctr),
		      "error setting trust account password");

	/* Why do we have to try to (re-)set the ACB to be the same as what
	   we passed in the samr_create_dom_user() call?  When a NT
	   workstation is joined to a domain by an administrator the
	   acb_info is set to 0x80.  For a normal user with "Add
	   workstations to the domain" rights the acb_info is 0x84.  I'm
	   not sure whether it is supposed to make a difference or not.  NT
	   seems to cope with either value so don't bomb out if the set
	   userinfo2 level 0x10 fails.  -tpot */

	ZERO_STRUCT(ctr);
	ctr.switch_value = 0x10;
	ctr.info.id10 = &p10;

	init_sam_user_info10(&p10, acb_info);

	/* Ignoring the return value is necessary for joining a domain
	   as a normal user with "Add workstation to domain" privilege. */

	result = cli_samr_set_userinfo2(cli, mem_ctx, &user_pol, 0x10, 
					&cli->user_session_key, &ctr);

	/* Now check the whole process from top-to-bottom */
	cli_samr_close(cli, mem_ctx, &user_pol);
	cli_nt_session_close(cli); /* Done with this pipe */

	if (!cli_nt_session_open(cli, PI_NETLOGON)) {
		DEBUG(0,("Error connecting to NETLOGON pipe\n"));
		goto done;
	}

	/* ensure that schannel uses the right domain */
	fstrcpy(cli->domain, domain);

	result = cli_nt_establish_netlogon(cli, sec_channel_type, 
					   md4_trust_password);

	if (!NT_STATUS_IS_OK(result)) {
		DEBUG(0, ("Error domain join verification (reused connection): %s\n\n",
			  nt_errstr(result)));

		if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) &&
		     (sec_channel_type == SEC_CHAN_BDC) ) {
			d_printf("Please make sure that no computer account\n"
				 "named like this machine (%s) exists in the domain\n",
				 global_myname());
		}

		goto done;
	}

	/* Now store the secret in the secrets database */

	strupper_m(domain);

	if (!secrets_store_domain_sid(domain, domain_sid)) {
		DEBUG(0, ("error storing domain sid for %s\n", domain));
		goto done;
	}

	if (!secrets_store_machine_password(clear_trust_password, domain, sec_channel_type)) {
		DEBUG(0, ("error storing plaintext domain secrets for %s\n", domain));
	}

	/* double-check, connection from scratch */
	retval = net_rpc_join_ok(domain);
	
done:
	/* Close down pipe - this will clean up open policy handles */

	if (cli->nt_pipe_fnum[cli->pipe_idx])
		cli_nt_session_close(cli);

	/* Display success or failure */

	if (retval != 0) {
		fprintf(stderr,"Unable to join domain %s.\n",domain);
	} else {
		printf("Joined domain %s.\n",domain);
	}
	
	cli_shutdown(cli);

	SAFE_FREE(clear_trust_password);

	return retval;
}
Example #18
0
static int calc_ntlmv2_hash(struct cifsSesInfo *ses, char *ntlmv2_hash,
			    const struct nls_table *nls_cp)
{
	int rc = 0;
	int len;
	char nt_hash[CIFS_NTHASH_SIZE];
	wchar_t *user;
	wchar_t *domain;
	wchar_t *server;

	if (!ses->server->secmech.sdeschmacmd5) {
		cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n");
		return -1;
	}

	/* calculate md4 hash of password */
	E_md4hash(ses->password, nt_hash);

	crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash,
				CIFS_NTHASH_SIZE);

	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
	if (rc) {
		cERROR(1, "calc_ntlmv2_hash: could not init hmacmd5\n");
		return rc;
	}

	/* convert ses->userName to unicode and uppercase */
	len = strlen(ses->userName);
	user = kmalloc(2 + (len * 2), GFP_KERNEL);
	if (user == NULL) {
		cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n");
		rc = -ENOMEM;
		goto calc_exit_2;
	}
	len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp);
	UniStrupr(user);

	crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
				(char *)user, 2 * len);

	/* convert ses->domainName to unicode and uppercase */
	if (ses->domainName) {
		len = strlen(ses->domainName);

		domain = kmalloc(2 + (len * 2), GFP_KERNEL);
		if (domain == NULL) {
			cERROR(1, "calc_ntlmv2_hash: domain mem alloc failure");
			rc = -ENOMEM;
			goto calc_exit_1;
		}
		len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len,
					nls_cp);
		crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
					(char *)domain, 2 * len);
		kfree(domain);
	} else if (ses->serverName) {
		len = strlen(ses->serverName);

		server = kmalloc(2 + (len * 2), GFP_KERNEL);
		if (server == NULL) {
			cERROR(1, "calc_ntlmv2_hash: server mem alloc failure");
			rc = -ENOMEM;
			goto calc_exit_1;
		}
		len = cifs_strtoUCS((__le16 *)server, ses->serverName, len,
					nls_cp);
		crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
					(char *)server, 2 * len);
		kfree(server);
	}

	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
					ntlmv2_hash);

calc_exit_1:
	kfree(user);
calc_exit_2:
	return rc;
}
Example #19
0
int net_rpc_join_newstyle(struct net_context *c, int argc, const char **argv)
{

	/* libsmb variables */

	struct cli_state *cli;
	TALLOC_CTX *mem_ctx;
        uint32 acb_info = ACB_WSTRUST;
	uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
	enum netr_SchannelType sec_channel_type;
	struct rpc_pipe_client *pipe_hnd = NULL;
	struct dcerpc_binding_handle *b = NULL;

	/* rpc variables */

	struct policy_handle lsa_pol, sam_pol, domain_pol, user_pol;
	struct dom_sid *domain_sid;
	uint32 user_rid;

	/* Password stuff */

	char *clear_trust_password = NULL;
	struct samr_CryptPassword crypt_pwd;
	uchar md4_trust_password[16];
	union samr_UserInfo set_info;

	/* Misc */

	NTSTATUS status, result;
	int retval = 1;
	const char *domain = NULL;
	char *acct_name;
	struct lsa_String lsa_acct_name;
	uint32 acct_flags=0;
	uint32_t access_granted = 0;
	union lsa_PolicyInformation *info = NULL;
	struct samr_Ids user_rids;
	struct samr_Ids name_types;


	/* check what type of join */
	if (argc >= 0) {
		sec_channel_type = get_sec_channel_type(argv[0]);
	} else {
		sec_channel_type = get_sec_channel_type(NULL);
	}

	switch (sec_channel_type) {
	case SEC_CHAN_WKSTA:
		acb_info = ACB_WSTRUST;
		break;
	case SEC_CHAN_BDC:
		acb_info = ACB_SVRTRUST;
		break;
#if 0
	case SEC_CHAN_DOMAIN:
		acb_info = ACB_DOMTRUST;
		break;
#endif
	default:
		DEBUG(0,("secure channel type %d not yet supported\n",
			sec_channel_type));
		break;
	}

	/* Make authenticated connection to remote machine */

	status = net_make_ipc_connection(c, NET_FLAGS_PDC, &cli);
	if (!NT_STATUS_IS_OK(status)) {
		return 1;
	}

	if (!(mem_ctx = talloc_init("net_rpc_join_newstyle"))) {
		DEBUG(0, ("Could not initialise talloc context\n"));
		goto done;
	}

	/* Fetch domain sid */

	status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
					  &pipe_hnd);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n",
			nt_errstr(status) ));
		goto done;
	}

	b = pipe_hnd->binding_handle;

	CHECK_RPC_ERR(rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
					  SEC_FLAG_MAXIMUM_ALLOWED,
					  &lsa_pol),
		      "error opening lsa policy handle");

	CHECK_DCERPC_ERR(dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
						    &lsa_pol,
						    LSA_POLICY_INFO_ACCOUNT_DOMAIN,
						    &info,
						    &result),
		      "error querying info policy");

	domain = info->account_domain.name.string;
	domain_sid = info->account_domain.sid;

	dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result);
	TALLOC_FREE(pipe_hnd); /* Done with this pipe */

	/* Bail out if domain didn't get set. */
	if (!domain) {
		DEBUG(0, ("Could not get domain name.\n"));
		goto done;
	}

	/* Create domain user */
	status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
					  &pipe_hnd);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
			nt_errstr(status) ));
		goto done;
	}

	b = pipe_hnd->binding_handle;

	CHECK_DCERPC_ERR(dcerpc_samr_Connect2(b, mem_ctx,
					      pipe_hnd->desthost,
					      SAMR_ACCESS_ENUM_DOMAINS
					      | SAMR_ACCESS_LOOKUP_DOMAIN,
					      &sam_pol,
					      &result),
		      "could not connect to SAM database");


	CHECK_DCERPC_ERR(dcerpc_samr_OpenDomain(b, mem_ctx,
						&sam_pol,
						SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
						| SAMR_DOMAIN_ACCESS_CREATE_USER
						| SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
						domain_sid,
						&domain_pol,
						&result),
		      "could not open domain");

	/* Create domain user */
	if ((acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname())) == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}
	strlower_m(acct_name);

	init_lsa_String(&lsa_acct_name, acct_name);

	acct_flags = SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
		     SEC_STD_WRITE_DAC | SEC_STD_DELETE |
		     SAMR_USER_ACCESS_SET_PASSWORD |
		     SAMR_USER_ACCESS_GET_ATTRIBUTES |
		     SAMR_USER_ACCESS_SET_ATTRIBUTES;

	DEBUG(10, ("Creating account with flags: %d\n",acct_flags));

	status = dcerpc_samr_CreateUser2(b, mem_ctx,
					 &domain_pol,
					 &lsa_acct_name,
					 acb_info,
					 acct_flags,
					 &user_pol,
					 &access_granted,
					 &user_rid,
					 &result);
	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}
	if (!NT_STATUS_IS_OK(result) &&
	    !NT_STATUS_EQUAL(result, NT_STATUS_USER_EXISTS)) {
		status = result;
		d_fprintf(stderr,_("Creation of workstation account failed\n"));

		/* If NT_STATUS_ACCESS_DENIED then we have a valid
		   username/password combo but the user does not have
		   administrator access. */

		if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
			d_fprintf(stderr, _("User specified does not have "
					    "administrator privileges\n"));

		goto done;
	}

	/* We *must* do this.... don't ask... */

	if (NT_STATUS_IS_OK(result)) {
		dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
	}

	CHECK_DCERPC_ERR_DEBUG(dcerpc_samr_LookupNames(b, mem_ctx,
						       &domain_pol,
						       1,
						       &lsa_acct_name,
						       &user_rids,
						       &name_types,
						       &result),
			    ("error looking up rid for user %s: %s/%s\n",
			     acct_name, nt_errstr(status), nt_errstr(result)));

	if (name_types.ids[0] != SID_NAME_USER) {
		DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types.ids[0]));
		goto done;
	}

	user_rid = user_rids.ids[0];

	/* Open handle on user */

	CHECK_DCERPC_ERR_DEBUG(
		dcerpc_samr_OpenUser(b, mem_ctx,
				     &domain_pol,
				     SEC_FLAG_MAXIMUM_ALLOWED,
				     user_rid,
				     &user_pol,
				     &result),
		("could not re-open existing user %s: %s/%s\n",
		 acct_name, nt_errstr(status), nt_errstr(result)));
	
	/* Create a random machine account password */

	clear_trust_password = generate_random_str(talloc_tos(), DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
	E_md4hash(clear_trust_password, md4_trust_password);

	/* Set password on machine account */

	init_samr_CryptPassword(clear_trust_password,
				&cli->user_session_key,
				&crypt_pwd);

	set_info.info24.password = crypt_pwd;
	set_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;

	CHECK_DCERPC_ERR(dcerpc_samr_SetUserInfo2(b, mem_ctx,
						  &user_pol,
						  24,
						  &set_info,
						  &result),
		      "error setting trust account password");

	/* Why do we have to try to (re-)set the ACB to be the same as what
	   we passed in the samr_create_dom_user() call?  When a NT
	   workstation is joined to a domain by an administrator the
	   acb_info is set to 0x80.  For a normal user with "Add
	   workstations to the domain" rights the acb_info is 0x84.  I'm
	   not sure whether it is supposed to make a difference or not.  NT
	   seems to cope with either value so don't bomb out if the set
	   userinfo2 level 0x10 fails.  -tpot */

	set_info.info16.acct_flags = acb_info;

	/* Ignoring the return value is necessary for joining a domain
	   as a normal user with "Add workstation to domain" privilege. */

	status = dcerpc_samr_SetUserInfo(b, mem_ctx,
					 &user_pol,
					 16,
					 &set_info,
					 &result);

	dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
	TALLOC_FREE(pipe_hnd); /* Done with this pipe */

	/* Now check the whole process from top-to-bottom */

	status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
					  &pipe_hnd);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0,("Error connecting to NETLOGON pipe. Error was %s\n",
			nt_errstr(status) ));
		goto done;
	}

	status = rpccli_netlogon_setup_creds(pipe_hnd,
					cli->desthost, /* server name */
					domain,        /* domain */
					global_myname(), /* client name */
					global_myname(), /* machine account name */
                                        md4_trust_password,
                                        sec_channel_type,
                                        &neg_flags);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("Error in domain join verification (credential setup failed): %s\n\n",
			  nt_errstr(status)));

		if ( NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
		     (sec_channel_type == SEC_CHAN_BDC) ) {
			d_fprintf(stderr, _("Please make sure that no computer "
					    "account\nnamed like this machine "
					    "(%s) exists in the domain\n"),
				 global_myname());
		}

		goto done;
	}

	/* We can only check the schannel connection if the client is allowed
	   to do this and the server supports it. If not, just assume success
	   (after all the rpccli_netlogon_setup_creds() succeeded, and we'll
	   do the same again (setup creds) in net_rpc_join_ok(). JRA. */

	if (lp_client_schannel() && (neg_flags & NETLOGON_NEG_SCHANNEL)) {
		struct rpc_pipe_client *netlogon_schannel_pipe;

		status = cli_rpc_pipe_open_schannel_with_key(
			cli, &ndr_table_netlogon.syntax_id, NCACN_NP,
			DCERPC_AUTH_LEVEL_PRIVACY, domain, &pipe_hnd->dc,
			&netlogon_schannel_pipe);

		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0, ("Error in domain join verification (schannel setup failed): %s\n\n",
				  nt_errstr(status)));

			if ( NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
			     (sec_channel_type == SEC_CHAN_BDC) ) {
				d_fprintf(stderr, _("Please make sure that no "
						    "computer account\nnamed "
						    "like this machine (%s) "
						    "exists in the domain\n"),
					 global_myname());
			}

			goto done;
		}
		TALLOC_FREE(netlogon_schannel_pipe);
	}

	TALLOC_FREE(pipe_hnd);

	/* Now store the secret in the secrets database */

	strupper_m(CONST_DISCARD(char *, domain));

	if (!secrets_store_domain_sid(domain, domain_sid)) {
		DEBUG(0, ("error storing domain sid for %s\n", domain));
		goto done;
	}

	if (!secrets_store_machine_password(clear_trust_password, domain, sec_channel_type)) {
		DEBUG(0, ("error storing plaintext domain secrets for %s\n", domain));
	}

	/* double-check, connection from scratch */
	status = net_rpc_join_ok(c, domain, cli->desthost, &cli->dest_ss);
	retval = NT_STATUS_IS_OK(status) ? 0 : -1;

done:

	/* Display success or failure */

	if (domain) {
		if (retval != 0) {
			fprintf(stderr,_("Unable to join domain %s.\n"),domain);
		} else {
			printf(_("Joined domain %s.\n"),domain);
		}
	}

	cli_shutdown(cli);

	TALLOC_FREE(clear_trust_password);

	return retval;
}
Example #20
0
NTSTATUS dcerpc_samr_chgpasswd_user2(struct dcerpc_binding_handle *h,
				     TALLOC_CTX *mem_ctx,
				     const char *srv_name_slash,
				     const char *username,
				     const char *newpassword,
				     const char *oldpassword,
				     NTSTATUS *presult)
{
	NTSTATUS status;
	struct samr_CryptPassword new_nt_password;
	struct samr_CryptPassword new_lm_password;
	struct samr_Password old_nt_hash_enc;
	struct samr_Password old_lanman_hash_enc;

	uint8_t old_nt_hash[16];
	uint8_t old_lanman_hash[16];
	uint8_t new_nt_hash[16];
	uint8_t new_lanman_hash[16];
	struct lsa_String server, account;

	DEBUG(10,("rpccli_samr_chgpasswd_user2\n"));

	init_lsa_String(&server, srv_name_slash);
	init_lsa_String(&account, username);

	/* Calculate the MD4 hash (NT compatible) of the password */
	E_md4hash(oldpassword, old_nt_hash);
	E_md4hash(newpassword, new_nt_hash);

	if (lp_client_lanman_auth() &&
	    E_deshash(newpassword, new_lanman_hash) &&
	    E_deshash(oldpassword, old_lanman_hash)) {
		/* E_deshash returns false for 'long' passwords (> 14
		   DOS chars).  This allows us to match Win2k, which
		   does not store a LM hash for these passwords (which
		   would reduce the effective password length to 14) */

		encode_pw_buffer(new_lm_password.data, newpassword, STR_UNICODE);

		arcfour_crypt(new_lm_password.data, old_nt_hash, 516);
		E_old_pw_hash(new_nt_hash, old_lanman_hash, old_lanman_hash_enc.hash);
	} else {
		ZERO_STRUCT(new_lm_password);
		ZERO_STRUCT(old_lanman_hash_enc);
	}

	encode_pw_buffer(new_nt_password.data, newpassword, STR_UNICODE);

	arcfour_crypt(new_nt_password.data, old_nt_hash, 516);
	E_old_pw_hash(new_nt_hash, old_nt_hash, old_nt_hash_enc.hash);

	status = dcerpc_samr_ChangePasswordUser2(h,
						 mem_ctx,
						 &server,
						 &account,
						 &new_nt_password,
						 &old_nt_hash_enc,
						 true,
						 &new_lm_password,
						 &old_lanman_hash_enc,
						 presult);

	return status;
}
Example #21
0
/*
 * do a password change using DCERPC/SAMR calls
 * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
 * 2. try samr_ChangePasswordUser3
 * 3. try samr_ChangePasswordUser2
 * 4. try samr_OemChangePasswordUser2
 * (not yet: 5. try samr_ChangePasswordUser)
 */
static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
{
        NTSTATUS status;
	struct libnet_RpcConnect c;
#if 0
	struct policy_handle user_handle;
	struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
	struct samr_ChangePasswordUser pw;
#endif
	struct samr_OemChangePasswordUser2 oe2;
	struct samr_ChangePasswordUser2 pw2;
	struct samr_ChangePasswordUser3 pw3;
	struct lsa_String server, account;
	struct lsa_AsciiString a_server, a_account;
	struct samr_CryptPassword nt_pass, lm_pass;
	struct samr_Password nt_verifier, lm_verifier;
	uint8_t old_nt_hash[16], new_nt_hash[16];
	uint8_t old_lm_hash[16], new_lm_hash[16];
	struct samr_DomInfo1 *dominfo = NULL;
	struct userPwdChangeFailureInformation *reject = NULL;

	ZERO_STRUCT(c);

	/* prepare connect to the SAMR pipe of the users domain PDC */
	c.level                    = LIBNET_RPC_CONNECT_PDC;
	c.in.name                  = r->samr.in.domain_name;
	c.in.dcerpc_iface     	   = &ndr_table_samr;
	c.in.dcerpc_flags          = DCERPC_ANON_FALLBACK;

	/* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
	status = libnet_RpcConnect(ctx, mem_ctx, &c);
	if (!NT_STATUS_IS_OK(status)) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
						"Connection to SAMR pipe of PDC of domain '%s' failed: %s",
						r->samr.in.domain_name, nt_errstr(status));
		return status;
	}

	/* prepare password change for account */
	server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe));
	account.string = r->samr.in.account_name;

	E_md4hash(r->samr.in.oldpassword, old_nt_hash);
	E_md4hash(r->samr.in.newpassword, new_nt_hash);

	E_deshash(r->samr.in.oldpassword, old_lm_hash);
	E_deshash(r->samr.in.newpassword, new_lm_hash);

	/* prepare samr_ChangePasswordUser3 */
	encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_UNICODE);
	arcfour_crypt(lm_pass.data, old_nt_hash, 516);
	E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);

	encode_pw_buffer(nt_pass.data,  r->samr.in.newpassword, STR_UNICODE);
	arcfour_crypt(nt_pass.data, old_nt_hash, 516);
	E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);

	pw3.in.server = &server;
	pw3.in.account = &account;
	pw3.in.nt_password = &nt_pass;
	pw3.in.nt_verifier = &nt_verifier;
	pw3.in.lm_change = 1;
	pw3.in.lm_password = &lm_pass;
	pw3.in.lm_verifier = &lm_verifier;
	pw3.in.password3 = NULL;
	pw3.out.dominfo = &dominfo;
	pw3.out.reject = &reject;

	/* 2. try samr_ChangePasswordUser3 */
	status = dcerpc_samr_ChangePasswordUser3(c.out.dcerpc_pipe, mem_ctx, &pw3);
	if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
		if (!NT_STATUS_IS_OK(status)) {
			r->samr.out.error_string = talloc_asprintf(mem_ctx,
								   "samr_ChangePasswordUser3 failed: %s",
								   nt_errstr(status));
			r->samr.out.error_string = talloc_asprintf(mem_ctx,
								   "samr_ChangePasswordUser3 for '%s\\%s' failed: %s",
								   r->samr.in.domain_name, r->samr.in.account_name, 
								   nt_errstr(status));
		}
		goto disconnect;
	} 

	/* prepare samr_ChangePasswordUser2 */
	encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII|STR_TERMINATE);
	arcfour_crypt(lm_pass.data, old_lm_hash, 516);
	E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);

	encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE);
	arcfour_crypt(nt_pass.data, old_nt_hash, 516);
	E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);

	pw2.in.server = &server;
	pw2.in.account = &account;
	pw2.in.nt_password = &nt_pass;
	pw2.in.nt_verifier = &nt_verifier;
	pw2.in.lm_change = 1;
	pw2.in.lm_password = &lm_pass;
	pw2.in.lm_verifier = &lm_verifier;

	/* 3. try samr_ChangePasswordUser2 */
	status = dcerpc_samr_ChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &pw2);
	if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
		if (!NT_STATUS_IS_OK(status)) {
			r->samr.out.error_string = talloc_asprintf(mem_ctx,
								   "samr_ChangePasswordUser2 for '%s\\%s' failed: %s",
								   r->samr.in.domain_name, r->samr.in.account_name, 
								   nt_errstr(status));
		}
		goto disconnect;
	}


	/* prepare samr_OemChangePasswordUser2 */
	a_server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe));
	a_account.string = r->samr.in.account_name;

	encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII);
	arcfour_crypt(lm_pass.data, old_lm_hash, 516);
	E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);

	oe2.in.server = &a_server;
	oe2.in.account = &a_account;
	oe2.in.password = &lm_pass;
	oe2.in.hash = &lm_verifier;

	/* 4. try samr_OemChangePasswordUser2 */
	status = dcerpc_samr_OemChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &oe2);
	if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
		if (!NT_STATUS_IS_OK(oe2.out.result)) {
			r->samr.out.error_string = talloc_asprintf(mem_ctx,
								   "samr_OemChangePasswordUser2 for '%s\\%s' failed: %s",
								   r->samr.in.domain_name, r->samr.in.account_name, 
								   nt_errstr(status));
		}
		goto disconnect;
	}

#if 0
	/* prepare samr_ChangePasswordUser */
	E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
	E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
	E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
	E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
	E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
	E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);

	/* TODO: ask for a user_handle */
	pw.in.handle = &user_handle;
	pw.in.lm_present = 1;
	pw.in.old_lm_crypted = &hash1;
	pw.in.new_lm_crypted = &hash2;
	pw.in.nt_present = 1;
	pw.in.old_nt_crypted = &hash3;
	pw.in.new_nt_crypted = &hash4;
	pw.in.cross1_present = 1;
	pw.in.nt_cross = &hash5;
	pw.in.cross2_present = 1;
	pw.in.lm_cross = &hash6;

	/* 5. try samr_ChangePasswordUser */
	status = dcerpc_samr_ChangePasswordUser(c.pdc.out.dcerpc_pipe, mem_ctx, &pw);
	if (!NT_STATUS_IS_OK(status)) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
						"samr_ChangePasswordUser failed: %s",
						nt_errstr(status));
		goto disconnect;
	}

	/* check result of samr_ChangePasswordUser */
	if (!NT_STATUS_IS_OK(pw.out.result)) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
						"samr_ChangePasswordUser for '%s\\%s' failed: %s",
						r->samr.in.domain_name, r->samr.in.account_name, 
						nt_errstr(pw.out.result));
		if (NT_STATUS_EQUAL(pw.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
			status = pw.out.result;
			goto disconnect;
		}
		goto disconnect;
	}
#endif
disconnect:
	/* close connection */
	talloc_free(c.out.dcerpc_pipe);

	return status;
}