📄 vncclient.cpp
字号:
//
BOOL
vncClientThread::AuthenticateNone()
{
if (m_client->m_protocol_minor_version >= 8) {
CARD32 secResult = Swap32IfLE(rfbAuthOK);
if (!m_socket->SendExact((char *)&secResult, sizeof(secResult)))
return FALSE;
}
return TRUE;
}
//
// Perform standard VNC authentication
//
BOOL
vncClientThread::AuthenticateVNC()
{
BOOL auth_ok = FALSE;
// Retrieve local passwords
char password[MAXPWLEN];
BOOL password_set = m_server->GetPassword(password);
vncPasswd::ToText plain(password);
BOOL password_viewonly_set = m_server->GetPasswordViewOnly(password);
vncPasswd::ToText plain_viewonly(password);
// Now create a 16-byte challenge
char challenge[16];
char challenge_viewonly[16];
vncRandomBytes((BYTE *)&challenge);
memcpy(challenge_viewonly, challenge, 16);
// Send the challenge to the client
if (!m_socket->SendExact(challenge, sizeof(challenge)))
return FALSE;
// Read the response
char response[16];
if (!m_socket->ReadExact(response, sizeof(response)))
return FALSE;
// Encrypt the challenge bytes
vncEncryptBytes((BYTE *)&challenge, plain);
// Compare them to the response
if (password_set && memcmp(challenge, response, sizeof(response)) == 0) {
auth_ok = TRUE;
} else {
// Check against the view-only password
vncEncryptBytes((BYTE *)&challenge_viewonly, plain_viewonly);
if (password_viewonly_set && memcmp(challenge_viewonly, response, sizeof(response)) == 0) {
m_client->EnablePointer(FALSE);
m_client->EnableKeyboard(FALSE);
auth_ok = TRUE;
}
}
// Did the authentication work?
CARD32 secResult;
if (!auth_ok) {
vnclog.Print(LL_CONNERR, VNCLOG("authentication failed\n"));
secResult = Swap32IfLE(rfbAuthFailed);
m_socket->SendExact((char *)&secResult, sizeof(secResult));
SendTextStringMessage("Authentication failed");
return FALSE;
} else {
// Tell the client we're ok
secResult = Swap32IfLE(rfbAuthOK);
if (!m_socket->SendExact((char *)&secResult, sizeof(secResult)))
return FALSE;
}
return TRUE;
}
//
// Read client initialisation message
//
BOOL
vncClientThread::ReadClientInit()
{
// Read the client's initialisation message
rfbClientInitMsg client_ini;
if (!m_socket->ReadExact((char *)&client_ini, sz_rfbClientInitMsg))
return FALSE;
// If the client wishes to have exclusive access then remove other clients
if (!client_ini.shared && !m_shared)
{
// Which client takes priority, existing or incoming?
if (m_server->ConnectPriority() < 1) {
// Incoming
vnclog.Print(LL_INTINFO, VNCLOG("non-shared connection - disconnecting old clients\n"));
m_server->KillAuthClients();
} else if (m_server->ConnectPriority() > 1) {
// Existing
if (m_server->AuthClientCount() > 0) {
vnclog.Print(LL_CLIENTS, VNCLOG("connections already exist - client rejected\n"));
return FALSE;
}
}
}
// Tell the server that this client is ok
return m_server->Authenticated(m_client->GetClientId());
}
//
// Advertise our messaging capabilities (protocol version 3.7+).
//
BOOL
vncClientThread::SendInteractionCaps()
{
// Update these constants on changing capability lists!
const int MAX_SMSG_CAPS = 4;
const int MAX_CMSG_CAPS = 6;
const int MAX_ENC_CAPS = 14;
int i;
// Supported server->client message types
rfbCapabilityInfo smsg_list[MAX_SMSG_CAPS];
i = 0;
if (m_server->FileTransfersEnabled() && m_client->IsInputEnabled()) {
SetCapInfo(&smsg_list[i++], rfbFileListData, rfbTightVncVendor);
SetCapInfo(&smsg_list[i++], rfbFileDownloadData, rfbTightVncVendor);
SetCapInfo(&smsg_list[i++], rfbFileUploadCancel, rfbTightVncVendor);
SetCapInfo(&smsg_list[i++], rfbFileDownloadFailed, rfbTightVncVendor);
}
int nServerMsgs = i;
if (nServerMsgs > MAX_SMSG_CAPS) {
vnclog.Print(LL_INTERR,
VNCLOG("assertion failed, nServerMsgs > MAX_SMSG_CAPS\n"));
return FALSE;
}
// Supported client->server message types
rfbCapabilityInfo cmsg_list[MAX_CMSG_CAPS];
i = 0;
if (m_server->FileTransfersEnabled() && m_client->IsInputEnabled()) {
SetCapInfo(&cmsg_list[i++], rfbFileListRequest, rfbTightVncVendor);
SetCapInfo(&cmsg_list[i++], rfbFileDownloadRequest,rfbTightVncVendor);
SetCapInfo(&cmsg_list[i++], rfbFileUploadRequest, rfbTightVncVendor);
SetCapInfo(&cmsg_list[i++], rfbFileUploadData, rfbTightVncVendor);
SetCapInfo(&cmsg_list[i++], rfbFileDownloadCancel, rfbTightVncVendor);
SetCapInfo(&cmsg_list[i++], rfbFileUploadFailed, rfbTightVncVendor);
}
int nClientMsgs = i;
if (nClientMsgs > MAX_CMSG_CAPS) {
vnclog.Print(LL_INTERR,
VNCLOG("assertion failed, nClientMsgs > MAX_CMSG_CAPS\n"));
return FALSE;
}
// Encoding types
rfbCapabilityInfo enc_list[MAX_ENC_CAPS];
i = 0;
SetCapInfo(&enc_list[i++], rfbEncodingCopyRect, rfbStandardVendor);
SetCapInfo(&enc_list[i++], rfbEncodingRRE, rfbStandardVendor);
SetCapInfo(&enc_list[i++], rfbEncodingCoRRE, rfbStandardVendor);
SetCapInfo(&enc_list[i++], rfbEncodingHextile, rfbStandardVendor);
SetCapInfo(&enc_list[i++], rfbEncodingZlib, rfbTridiaVncVendor);
SetCapInfo(&enc_list[i++], rfbEncodingZlibHex, rfbTridiaVncVendor);
SetCapInfo(&enc_list[i++], rfbEncodingTight, rfbTightVncVendor);
SetCapInfo(&enc_list[i++], rfbEncodingCompressLevel0, rfbTightVncVendor);
SetCapInfo(&enc_list[i++], rfbEncodingQualityLevel0, rfbTightVncVendor);
SetCapInfo(&enc_list[i++], rfbEncodingXCursor, rfbTightVncVendor);
SetCapInfo(&enc_list[i++], rfbEncodingRichCursor, rfbTightVncVendor);
SetCapInfo(&enc_list[i++], rfbEncodingPointerPos, rfbTightVncVendor);
SetCapInfo(&enc_list[i++], rfbEncodingLastRect, rfbTightVncVendor);
SetCapInfo(&enc_list[i++], rfbEncodingNewFBSize, rfbTightVncVendor);
int nEncodings = i;
if (nEncodings > MAX_ENC_CAPS) {
vnclog.Print(LL_INTERR,
VNCLOG("assertion failed, nEncodings > MAX_ENC_CAPS\n"));
return FALSE;
}
// Create and send the header structure
rfbInteractionCapsMsg intr_caps;
intr_caps.nServerMessageTypes = Swap16IfLE(nServerMsgs);
intr_caps.nClientMessageTypes = Swap16IfLE(nClientMsgs);
intr_caps.nEncodingTypes = Swap16IfLE(nEncodings);
intr_caps.pad = 0;
if (!m_socket->SendExact((char *)&intr_caps, sz_rfbInteractionCapsMsg))
return FALSE;
// Send the capability lists
if (nServerMsgs &&
!m_socket->SendExact((char *)&smsg_list[0],
sz_rfbCapabilityInfo * nServerMsgs))
return FALSE;
if (nClientMsgs &&
!m_socket->SendExact((char *)&cmsg_list[0],
sz_rfbCapabilityInfo * nClientMsgs))
return FALSE;
if (nEncodings &&
!m_socket->SendExact((char *)&enc_list[0],
sz_rfbCapabilityInfo * nEncodings))
return FALSE;
return TRUE;
}
void
ClearKeyState(BYTE key)
{
// This routine is used by the VNC client handler to clear the
// CAPSLOCK, NUMLOCK and SCROLL-LOCK states.
BYTE keyState[256];
GetKeyboardState((LPBYTE)&keyState);
if(keyState[key] & 1)
{
// Simulate the key being pressed
keybd_event(key, 0, KEYEVENTF_EXTENDEDKEY, 0);
// Simulate it being release
keybd_event(key, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}
void
vncClientThread::run(void *arg)
{
// All this thread does is go into a socket-recieve loop,
// waiting for stuff on the given socket
// IMPORTANT : ALWAYS call RemoveClient on the server before quitting
// this thread.
vnclog.Print(LL_CLIENTS, VNCLOG("client connected : %s (id %hd)\n"),
m_client->GetClientName(), m_client->GetClientId());
// Save the handle to the thread's original desktop
HDESK home_desktop = GetThreadDesktop(GetCurrentThreadId());
// To avoid people connecting and then halting the connection, set a timeout
if (!m_socket->SetTimeout(30000))
vnclog.Print(LL_INTERR,
VNCLOG("failed to set socket timeout, error=%d\n"),
GetLastError());
// Initially blacklist the client so that excess connections from it get dropped
m_server->AddAuthHostsBlacklist(m_client->GetClientName());
// LOCK INITIAL SETUP
// All clients have the m_protocol_ready flag set to FALSE initially, to prevent
// updates and suchlike interfering with the initial protocol negotiations.
// GET PROTOCOL VERSION
if (!InitVersion()) {
m_server->RemoveClient(m_client->GetClientId());
return;
}
// AUTHENTICATE LINK
if (!InitAuthenticate()) {
m_server->RemoveClient(m_client->GetClientId());
return;
}
// READ CLIENT INITIALIZATION MESSAGE
if (!ReadClientInit()) {
m_server->RemoveClient(m_client->GetClientId());
return;
}
// Authenticated OK - remove from blacklist and remove timeout
m_server->RemAuthHostsBlacklist(m_client->GetClientName());
m_socket->SetTimeout(m_server->AutoIdleDisconnectTimeout()*1000);
vnclog.Print(LL_INTINFO, VNCLOG("authenticated connection\n"));
// INIT PIXEL FORMAT
// Get the screen format
m_client->m_fullscreen = m_client->m_buffer->GetSize();
// Get the name of this desktop
char desktopname[MAX_COMPUTERNAME_LENGTH+1];
DWORD desktopnamelen = MAX_COMPUTERNAME_LENGTH + 1;
if (GetComputerName(desktopname, &desktopnamelen))
{
// Make the name lowercase
for (size_t x=0; x<strlen(desktopname); x++)
{
desktopname[x] = tolower(desktopname[x]);
}
}
else
{
strcpy(desktopname, "WinVNC");
}
// Send the server format message to the client
rfbServerInitMsg server_ini;
server_ini.format = m_client->m_buffer->GetLocalFormat();
// Endian swaps
RECT sharedRect;
sharedRect = m_server->GetSharedRect();
server_ini.framebufferWidth = Swap16IfLE(sharedRect.right- sharedRect.left);
server_ini.framebufferHeight = Swap16IfLE(sharedRect.bottom - sharedRect.top);
server_ini.format.redMax = Swap16IfLE(server_ini.format.redMax);
server_ini.format.greenMax = Swap16IfLE(server_ini.format.greenMax);
server_ini.format.blueMax = Swap16IfLE(server_ini.format.blueMax);
server_ini.nameLength = Swap32IfLE(strlen(desktopname));
if (!m_socket->SendExact((char *)&server_ini, sizeof(server_ini)))
{
m_server->RemoveClient(m_client->GetClientId());
return;
}
if (!m_socket->SendExact(desktopname, strlen(desktopname)))
{
m_server->RemoveClient(m_client->GetClientId());
return;
}
vnclog.Print(LL_INTINFO, VNCLOG("sent pixel format to client\n"));
// Inform the client about our interaction capabilities (protocol 3.7t)
if (m_client->m_protocol_tightvnc) {
if (!SendInteractionCaps()) {
m_server->RemoveClient(m_client->GetClientId());
return;
}
vnclog.Print(LL_INTINFO, VNCLOG("list of interaction capabilities sent\n"));
}
// UNLOCK INITIAL SETUP
// Initial negotiation is complete, so set the protocol ready flag
{
omni_mutex_lock l(m_client->m_regionLock);
m_client->m_protocol_ready = TRUE;
}
// Clear the CapsLock and NumLock keys
if (m_client->IsKeyboardEnabled())
{
ClearKeyState(VK_CAPITAL);
// *** JNW - removed because people complain it's wrong
//ClearKeyState(VK_NUMLOCK);
ClearKeyState(VK_SCROLL);
}
// MAIN LOOP
BOOL connected = TRUE;
while (connected)
{
rfbClientToServerMsg msg;
// Ensure that we're running in the correct desktop
if (!vncService::InputDesktopSelected())
if (!vncService::SelectDesktop(NULL))
break;
// Try to read a message ID
if (!m_socket->ReadExact((char *)&msg.type, sizeof(msg.type)))
{
connected = FALSE;
break;
}
// What to do is determined by the message id
switch(msg.type)
{
case rfbSetPixelFormat:
// Read the rest of the message:
if (!m_socket->ReadExact(((char *) &msg)+1, sz_rfbSetPixelFormatMsg-1))
{
connected = FALSE;
break;
}
// Swap the relevant bits.
msg.spf.format.redMax = Swap16IfLE(msg.spf.format.redMax);
msg.spf.format.greenMax = Swap16IfLE(msg.spf.format.greenMax);
msg.spf.format.blueMax = Swap16IfLE(msg.spf.format.blueMax);
{
omni_mutex_lock l(m_client->m_regionLock);
// Tell the buffer object of the change
if (!m_client->m_buffer->SetClientFormat(msg.spf.format))
{
vnclog.Print(LL_CONNERR, VNCLOG("remote pixel format invalid\n"));
connected = FALSE;
}
// Set the palette-changed flag, just in case...
m_client->m_palettechanged = TRUE;
}
break;
case rfbSetEncodings:
// Read the rest of the message:
if (!m_socket->ReadExact(((char *) &msg)+1, sz_rfbSetEncodingsMsg-1))
{
connected = FALSE;
break;
}
m_client->m_buffer->SetQualityLevel(-1);
m_client->m_buffer->SetCompressLevel(6);
m_client->m_buffer->EnableXCursor(FALSE);
m_client->m_buffer->EnableRichCursor(FALSE);
m_client->m_buffer->EnableLastRect(FALSE);
m_client->m_use_PointerPos = FALSE;
m_client->m_use_NewFBSize = FALSE;
m_client->m_cursor_update_pending = FALSE;
m_client->m_cursor_update_sent = FALSE;
m_client->m_cursor_pos_changed = FALSE;
// Read in the preferred encodings
msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings);
{
int x;
BOOL encoding_set = FALSE;
BOOL shapeupdates_requested = FALSE;
BOOL pointerpos_requested = FALSE;
{
omni_mutex_lock l(m_client->m_regionLock);
// By default, don't use copyrect!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -