static int nla_server_authenticate(rdpNla* nla)
{
	int res = -1;

	WINPR_ASSERT(nla);

	if (nla_server_init(nla) < 1)
		goto fail_auth;

	/* Client is starting, here es the state machine:
	 *
	 *  -- NLA_STATE_INITIAL	--> NLA_STATE_INITIAL
	 * ----->> sending...
	 *    ----->> protocol version 6
	 *    ----->> nego token
	 *    ----->> client nonce
	 * <<----- receiving...
	 *    <<----- protocol version 6
	 *    <<----- nego token
	 * ----->> sending...
	 *    ----->> protocol version 6
	 *    ----->> nego token
	 *    ----->> public key auth
	 *    ----->> client nonce
	 * -- NLA_STATE_NEGO_TOKEN	--> NLA_STATE_PUB_KEY_AUTH
	 * <<----- receiving...
	 *    <<----- protocol version 6
	 *    <<----- public key info
	 * ----->> sending...
	 *    ----->> protocol version 6
	 *    ----->> auth info
	 *    ----->> client nonce
	 * -- NLA_STATE_PUB_KEY_AUTH	--> NLA_STATE
	 */

	while (TRUE)
	{
		int rc = -1;
		SecBuffer inputBuffer = { 0 };
		SecBuffer outputBuffer = { 0 };
		SecBufferDesc inputBufferDesc = { 0 };
		SecBufferDesc outputBufferDesc = { 0 };

		/* receive authentication token */
		inputBufferDesc.ulVersion = SECBUFFER_VERSION;
		inputBufferDesc.cBuffers = 1;
		inputBufferDesc.pBuffers = &inputBuffer;

		if (nla_server_recv(nla) < 0)
			goto fail_auth;

		WLog_DBG(TAG, "Receiving Authentication Token");
		if (!nla_sec_buffer_alloc_from_buffer(&inputBuffer, &nla->negoToken, 0))
		{
			WLog_ERR(TAG, "CredSSP: invalid negoToken!");
			goto fail;
		}

		outputBufferDesc.ulVersion = SECBUFFER_VERSION;
		outputBufferDesc.cBuffers = 1;
		outputBufferDesc.pBuffers = &outputBuffer;

		if (!nla_sec_buffer_alloc(&outputBuffer, nla->cbMaxToken))
			goto fail;

		nla->status = nla->table->AcceptSecurityContext(
		    &nla->credentials, nla->haveContext ? &nla->context : NULL, &inputBufferDesc,
		    nla->fContextReq, SECURITY_NATIVE_DREP, &nla->context, &outputBufferDesc,
		    &nla->pfContextAttr, &nla->expiration);
		WLog_VRB(TAG, "AcceptSecurityContext status %s [0x%08" PRIX32 "]",
		         GetSecurityStatusString(nla->status), nla->status);

		if (!nla_sec_buffer_alloc_from_buffer(&nla->negoToken, &outputBuffer, 0))
			goto fail;

		if (nla->status == SEC_E_OK)
		{
			if (outputBuffer.cbBuffer != 0)
			{
				if (!nla_send(nla))
				{
					nla_buffer_free(nla);
					goto fail;
				}

				if (nla_server_recv(nla) < 0)
					goto fail;

				WLog_DBG(TAG, "Receiving pubkey Token");
			}

			nla->havePubKeyAuth = TRUE;
			nla->status = nla_query_context_sizes(nla);

			if (nla->status != SEC_E_OK)
				goto fail;

			if (nla->peerVersion < 5)
				nla->status = nla_decrypt_public_key_echo(nla);
			else
				nla->status = nla_decrypt_public_key_hash(nla);

			if (nla->status != SEC_E_OK)
			{
				WLog_ERR(TAG,
				         "Error: could not verify client's public key echo %s [0x%08" PRIX32 "]",
				         GetSecurityStatusString(nla->status), nla->status);
				goto fail;
			}

			sspi_SecBufferFree(&nla->negoToken);

			if (nla->peerVersion < 5)
				nla->status = nla_encrypt_public_key_echo(nla);
			else
				nla->status = nla_encrypt_public_key_hash(nla);

			if (nla->status != SEC_E_OK)
				goto fail;

			rc = 1;
		}
		else
		{
			rc = 0;
		}
	fail:
		sspi_SecBufferFree(&inputBuffer);
		sspi_SecBufferFree(&outputBuffer);
		if (rc < 0)
		{
			res = rc;
			goto fail_auth;
		}

		if ((nla->status != SEC_E_OK) && (nla->status != SEC_I_CONTINUE_NEEDED))
		{
			/* Special handling of these specific error codes as NTSTATUS_FROM_WIN32
			   unfortunately does not map directly to the corresponding NTSTATUS values
			 */
			switch (GetLastError())
			{
				case ERROR_PASSWORD_MUST_CHANGE:
					nla->errorCode = STATUS_PASSWORD_MUST_CHANGE;
					break;

				case ERROR_PASSWORD_EXPIRED:
					nla->errorCode = STATUS_PASSWORD_EXPIRED;
					break;

				case ERROR_ACCOUNT_DISABLED:
					nla->errorCode = STATUS_ACCOUNT_DISABLED;
					break;

				default:
					nla->errorCode = NTSTATUS_FROM_WIN32(GetLastError());
					break;
			}

			WLog_ERR(TAG, "AcceptSecurityContext status %s [0x%08" PRIX32 "]",
			         GetSecurityStatusString(nla->status), nla->status);
			nla_send(nla);
			goto fail_auth; /* Access Denied */
		}

		/* send authentication token */
		WLog_DBG(TAG, "Sending Authentication Token");

		if (!nla_send(nla))
		{
			nla_buffer_free(nla);
			goto fail_auth;
		}

		if (nla->status != SEC_I_CONTINUE_NEEDED)
			break;

		nla->haveContext = TRUE;
	}

	/* Receive encrypted credentials */
	if (!nla_server_recv_credentials(nla))
		goto fail_auth;

	res = 1;
fail_auth:
	nla_buffer_free(nla);
	return res;
}
static int nla_server_authenticate(rdpNla* nla)
{
	int res = -1;

	WINPR_ASSERT(nla);

	if (nla_server_init(nla) < 1)
		goto fail_auth;

	 

	while (TRUE)
	{
		int rc = -1;
		SecBuffer inputBuffer = { 0 };
		SecBuffer outputBuffer = { 0 };
		SecBufferDesc inputBufferDesc = { 0 };
		SecBufferDesc outputBufferDesc = { 0 };

		 
		inputBufferDesc.ulVersion = SECBUFFER_VERSION;
		inputBufferDesc.cBuffers = 1;
		inputBufferDesc.pBuffers = &inputBuffer;

		if (nla_server_recv(nla) < 0)
			goto fail_auth;

		WLog_DBG(TAG, "Receiving Authentication Token");
		if (!nla_sec_buffer_alloc_from_buffer(&inputBuffer, &nla->negoToken, 0))
		{
			WLog_ERR(TAG, "CredSSP: invalid negoToken!");
			goto fail;
		}

		outputBufferDesc.ulVersion = SECBUFFER_VERSION;
		outputBufferDesc.cBuffers = 1;
		outputBufferDesc.pBuffers = &outputBuffer;

		if (!nla_sec_buffer_alloc(&outputBuffer, nla->cbMaxToken))
			goto fail;

		nla->status = nla->table->AcceptSecurityContext(
		    &nla->credentials, nla->haveContext ? &nla->context : NULL, &inputBufferDesc,
		    nla->fContextReq, SECURITY_NATIVE_DREP, &nla->context, &outputBufferDesc,
		    &nla->pfContextAttr, &nla->expiration);
		WLog_VRB(TAG, "AcceptSecurityContext status %s [0x%08" PRIX32 "]",
		         GetSecurityStatusString(nla->status), nla->status);

		if (!nla_sec_buffer_alloc_from_buffer(&nla->negoToken, &outputBuffer, 0))
			goto fail;

		if (nla->status == SEC_E_OK)
		{
			if (outputBuffer.cbBuffer != 0)
			{
				if (!nla_send(nla))
				{
					nla_buffer_free(nla);
					goto fail;
				}

				if (nla_server_recv(nla) < 0)
					goto fail;

				WLog_DBG(TAG, "Receiving pubkey Token");
			}

			nla->havePubKeyAuth = TRUE;
			nla->status = nla_query_context_sizes(nla);

			if (nla->status != SEC_E_OK)
				goto fail;

			if (nla->peerVersion < 5)
				nla->status = nla_decrypt_public_key_echo(nla);
			else
				nla->status = nla_decrypt_public_key_hash(nla);

			if (nla->status != SEC_E_OK)
			{
				WLog_ERR(TAG,
				         "Error: could not verify client's public key echo %s [0x%08" PRIX32 "]",
				         GetSecurityStatusString(nla->status), nla->status);
				goto fail;
			}

			sspi_SecBufferFree(&nla->negoToken);

			if (nla->peerVersion < 5)
				nla->status = nla_encrypt_public_key_echo(nla);
			else
				nla->status = nla_encrypt_public_key_hash(nla);

			if (nla->status != SEC_E_OK)
				goto fail;

			rc = 1;
		}
		else
		{
			rc = 0;
		}
	fail:
		sspi_SecBufferFree(&inputBuffer);
		sspi_SecBufferFree(&outputBuffer);
		if (rc < 0)
		{
			res = rc;
			goto fail_auth;
		}

		if ((nla->status != SEC_E_OK) && (nla->status != SEC_I_CONTINUE_NEEDED))
		{
			 
			switch (GetLastError())
			{
				case ERROR_PASSWORD_MUST_CHANGE:
					nla->errorCode = STATUS_PASSWORD_MUST_CHANGE;
					break;

				case ERROR_PASSWORD_EXPIRED:
					nla->errorCode = STATUS_PASSWORD_EXPIRED;
					break;

				case ERROR_ACCOUNT_DISABLED:
					nla->errorCode = STATUS_ACCOUNT_DISABLED;
					break;

				default:
					nla->errorCode = NTSTATUS_FROM_WIN32(GetLastError());
					break;
			}

			WLog_ERR(TAG, "AcceptSecurityContext status %s [0x%08" PRIX32 "]",
			         GetSecurityStatusString(nla->status), nla->status);
			nla_send(nla);
			goto fail_auth;  
		}

		 
		WLog_DBG(TAG, "Sending Authentication Token");

		if (!nla_send(nla))
		{
			nla_buffer_free(nla);
			goto fail_auth;
		}

		if (nla->status != SEC_I_CONTINUE_NEEDED)
			break;

		nla->haveContext = TRUE;
	}

	 
	if (!nla_server_recv_credentials(nla))
		goto fail_auth;

	res = 1;
fail_auth:
	nla_buffer_free(nla);
	return res;
}