metasploit-framework/external/source/vncdll/winvnc/vncServer.cpp

1681 lines
36 KiB
C++

// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
//
// This file is part of the VNC system.
//
// The VNC system is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//
// TightVNC distribution homepage on the Web: http://www.tightvnc.com/
//
// If the source code for the VNC system is not available from the place
// whence you received this file, check http://www.uk.research.att.com/vnc or contact
// the authors on vnc@uk.research.att.com for information on obtaining it.
// vncServer.cpp
// vncServer class implementation
// Includes
#include "stdhdrs.h"
#include <omnithread.h>
#include <string.h>
#include <lmcons.h>
// Custom
#include "vncServer.h"
#include "vncSockConnect.h"
#include "vncCorbaConnect.h"
#include "vncClient.h"
#include "vncService.h"
// Constructor/destructor
vncServer::vncServer()
{
ResetPasswordsValidityInfo();
// Initialise some important stuffs...
m_socketConn = NULL;
m_corbaConn = NULL;
//m_httpConn = NULL;
m_desktop = NULL;
m_name = NULL;
SetName("");
m_port = DISPLAY_TO_PORT(0);
m_port_http = DISPLAY_TO_HPORT(0);
m_autoportselect = TRUE;
m_passwd_required = FALSE;
m_beepConnect = FALSE;
m_beepDisconnect = FALSE;
m_auth_hosts = 0;
m_blacklist = 0;
//{
// vncPasswd::FromClear clearPWD;
memcpy(m_password, "", MAXPWLEN);
m_password_set = FALSE;
memcpy(m_password_viewonly, "", MAXPWLEN);
m_password_viewonly_set = FALSE;
//}
m_querysetting = 2;
m_querytimeout = 10;
m_queryaccept = FALSE;
m_queryallownopass = FALSE;
// Autolock settings
m_lock_on_exit = 0;
// Set the polling mode options
m_poll_fullscreen = TRUE;
m_poll_foreground = TRUE;
m_poll_undercursor = TRUE;
m_poll_oneventonly = FALSE;
m_poll_consoleonly = FALSE;
m_dont_set_hooks = FALSE;
m_dont_use_driver = FALSE;
m_driver_direct_access_en = TRUE;
// General options
m_loopbackOnly = TRUE;
m_disableTrayIcon = TRUE;
m_loopback_allowed = TRUE;
m_httpd_enabled = FALSE;
m_httpd_params_enabled = FALSE;
m_lock_on_exit = 0;
m_connect_pri = 0;
// Set the input options
m_enable_remote_inputs = TRUE;
m_disable_local_inputs = FALSE;
// Clear the client mapping table
for (int x=0; x<MAX_CLIENTS; x++)
m_clientmap[x] = NULL;
m_nextid = 0;
// Signal set when a client quits
m_clientquitsig = new omni_condition(&m_clientsLock);
m_clients_disabled = FALSE;
m_local_input_priority = FALSE;
m_full_screen = TRUE;
m_WindowShared= FALSE;
m_hwndShared = NULL;
m_screen_area = FALSE;
m_primary_display_only_shared = FALSE;
m_disable_time = 3;
SetSharedRect(GetScreenRect());
SetPollingCycle(300);
PollingCycleChanged(false);
m_cursor_pos.x = 0;
m_cursor_pos.y = 0;
// initialize
m_enable_file_transfers = FALSE;
m_remove_wallpaper = FALSE;
m_blank_screen = FALSE;
#ifdef HORIZONLIVE
m_full_screen = FALSE;
m_WindowShared= TRUE;
m_local_input_priority = TRUE;
m_remote_mouse = 1;
m_remote_keyboard = 1;
#endif
m_wallpaper_wait = FALSE;
}
vncServer::~vncServer()
{
// If there is a socket_conn object then delete it
if (m_socketConn != NULL)
{
delete m_socketConn;
m_socketConn = NULL;
}
if (m_corbaConn != NULL)
{
delete m_corbaConn;
m_corbaConn = NULL;
}
/*if (m_httpConn != NULL)
{
delete m_httpConn;
m_httpConn = NULL;
}*/
// Remove any active clients!
KillAuthClients();
KillUnauthClients();
// Wait for all the clients to die
WaitUntilAuthEmpty();
WaitUntilUnauthEmpty();
// Don't free the desktop until no KillClient is likely to free it
{ omni_mutex_lock l(m_desktopLock);
if (m_desktop != NULL)
{
delete m_desktop;
m_desktop = NULL;
}
}
// Don't free the authhosts string until no more connections are possible
if (m_auth_hosts != 0)
{
free(m_auth_hosts);
m_auth_hosts = 0;
}
if (m_name != NULL)
{
free(m_name);
m_name = NULL;
}
if (m_clientquitsig != NULL)
{
delete m_clientquitsig;
m_clientquitsig = NULL;
}
}
// Client handling functions
void
vncServer::DisableClients(BOOL state)
{
m_clients_disabled = state;
}
BOOL
vncServer::ClientsDisabled()
{
return m_clients_disabled;
}
vncClientId vncServer::AddClient( AGENT_CTX * lpAgentContext )
{
vncClient *client = NULL;
VSocket * socket = NULL;
omni_mutex_lock l(m_clientsLock);
socket = new VSocket( &lpAgentContext->info, lpAgentContext->hCloseEvent );
// Try to allocate a client id...
vncClientId clientid = m_nextid;
do
{
clientid = (clientid+1) % MAX_CLIENTS;
if (clientid == m_nextid)
{
delete socket;
return -1;
}
}
while (m_clientmap[clientid] != NULL);
// Create a new client and add it to the relevant client list
client = new vncClient();
if (client == NULL) {
delete socket;
return -1;
}
// Set the client's settings
client->EnableKeyboard(TRUE && m_enable_remote_inputs);
client->EnablePointer(TRUE && m_enable_remote_inputs);
// Start the client
if (!client->Init(this, socket, TRUE, TRUE, clientid, lpAgentContext ))
{
// The client will delete the socket for us...
delete client;
return -1;
}
m_clientmap[clientid] = client;
// Add the client to unauth the client list
m_unauthClients.push_back(clientid);
// Notify anyone interested about this event
//DoNotify(WM_SRV_CLIENT_CONNECT, 0, 0);
return clientid;
}
BOOL
vncServer::Authenticated(vncClientId clientid)
{
vncClientList::iterator i;
BOOL authok = TRUE;
omni_mutex_lock l1(m_desktopLock);
omni_mutex_lock l2(m_clientsLock);
// Search the unauthenticated client list
for (i = m_unauthClients.begin(); i != m_unauthClients.end(); i++)
{
// Is this the right client?
if ((*i) == clientid)
{
vncClient *client = GetClient(clientid);
// Yes, so remove the client and add it to the auth list
m_unauthClients.erase(i);
// Create the screen handler if necessary
if (m_desktop == NULL)
{
if (RemoveWallpaperEnabled()) {
m_wallpaper_wait = TRUE;
//DoNotify(WM_SRV_CLIENT_HIDEWALLPAPER, 0, 0);
}
m_desktop = new vncDesktop();
if (m_desktop == NULL)
{
client->Kill();
authok = FALSE;
break;
}
if (!m_desktop->Init(this))
{
client->Kill();
authok = FALSE;
delete m_desktop;
m_desktop = NULL;
break;
}
}
// Create a buffer object for this client
vncBuffer *buffer = new vncBuffer(m_desktop);
if (buffer == NULL)
{
client->Kill();
authok = FALSE;
break;
}
// Tell the client about this new buffer
client->SetBuffer(buffer);
// Add the client to the auth list
m_authClients.push_back(clientid);
break;
}
}
// Notify anyone interested of this event
//DoNotify(WM_SRV_CLIENT_AUTHENTICATED, 0, 0);
// If so configured, beep to indicate the new connection is
// present.
if (authok && GetBeepConnect())
{
MessageBeep(MB_OK);
}
return authok;
}
void
vncServer::KillClient(vncClientId clientid)
{
vncClientList::iterator i;
BOOL done = FALSE;
omni_mutex_lock l(m_clientsLock);
// Find the client in one of the two lists
for (i = m_unauthClients.begin(); i != m_unauthClients.end(); i++)
{
// Is this the right client?
if ((*i) == clientid)
{
// Ask the client to die
vncClient *client = GetClient(clientid);
client->Kill();
done = TRUE;
break;
}
}
if (!done)
{
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
// Is this the right client?
if ((*i) == clientid)
{
// Yes, so kill it
vncClient *client = GetClient(clientid);
client->Kill();
done = TRUE;
break;
}
}
}
}
void
vncServer::KillAuthClients()
{
vncClientList::iterator i;
omni_mutex_lock l(m_clientsLock);
// Tell all the authorised clients to die!
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
// Kill the client
GetClient(*i)->Kill();
}
}
void
vncServer::KillUnauthClients()
{
vncClientList::iterator i;
omni_mutex_lock l(m_clientsLock);
// Tell all the authorised clients to die!
for (i = m_unauthClients.begin(); i != m_unauthClients.end(); i++)
{
// Kill the client
GetClient(*i)->Kill();
}
}
size_t
vncServer::AuthClientCount()
{
omni_mutex_lock l(m_clientsLock);
return m_authClients.size();
}
size_t
vncServer::UnauthClientCount()
{
omni_mutex_lock l(m_clientsLock);
return m_unauthClients.size();
}
void
vncServer::WaitUntilAuthEmpty()
{
omni_mutex_lock l(m_clientsLock);
// Wait for all the clients to exit
while (!m_authClients.empty())
{
// Wait for a client to quit
m_clientquitsig->wait();
}
}
void
vncServer::WaitUntilUnauthEmpty()
{
omni_mutex_lock l(m_clientsLock);
// Wait for all the clients to exit
while (!m_unauthClients.empty())
{
// Wait for a client to quit
m_clientquitsig->wait();
}
}
BOOL
vncServer::RemoteEventReceived()
{
vncClientList::iterator i;
BOOL result = FALSE;
omni_mutex_lock l(m_clientsLock);
// Iterate over the authorised clients
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
result = result || GetClient(*i)->RemoteEventReceived();
}
return result;
}
// Client info retrieval/setup
vncClient*
vncServer::GetClient(vncClientId clientid)
{
if ((clientid >= 0) && (clientid < MAX_CLIENTS))
return m_clientmap[clientid];
return NULL;
}
vncClientList
vncServer::ClientList()
{
vncClientList clients;
omni_mutex_lock l(m_clientsLock);
clients = m_authClients;
return clients;
}
void
vncServer::BlockRemoteInput(BOOL block)
{
omni_mutex_lock l(m_clientsLock);
vncClientList::iterator i;
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
GetClient(*i)->BlockInput(block);
}
const char*
vncServer::GetClientName(vncClientId clientid)
{
omni_mutex_lock l(m_clientsLock);
vncClient *client = GetClient(clientid);
if (client != NULL)
return client->GetClientName();
return NULL;
}
// RemoveClient should ONLY EVER be used by the client to remove itself.
void
vncServer::RemoveClient(vncClientId clientid)
{
vncClientList::iterator i;
BOOL done = FALSE;
omni_mutex_lock l1(m_desktopLock);
{ omni_mutex_lock l2(m_clientsLock);
// Find the client in one of the two lists
for (i = m_unauthClients.begin(); i != m_unauthClients.end(); i++)
{
// Is this the right client?
if ((*i) == clientid)
{
// Yes, so remove the client and kill it
m_unauthClients.erase(i);
m_clientmap[clientid] = NULL;
done = TRUE;
break;
}
}
if (!done)
{
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
// Is this the right client?
if ((*i) == clientid)
{
// Yes, so remove the client and kill it
m_authClients.erase(i);
m_clientmap[clientid] = NULL;
done = TRUE;
break;
}
}
}
// Signal that a client has quit
m_clientquitsig->signal();
} // Unlock the clientLock
// If so configured, beep to indicate the old connection is
// gone.
if (GetBeepDisconnect())
{
MessageBeep(MB_OK);
}
// Are there any authorised clients connected?
if (m_authClients.empty() && (m_desktop != NULL))
{
// Are there locksettings set?
if (LockSettings() == 1)
{
// Yes - lock the machine on disconnect!
vncService::LockWorkstation();
} else if (LockSettings() > 1)
{
char username[UNLEN+1];
vncService::CurrentUser((char *)&username, sizeof(username));
if (strcmp(username, "") != 0)
{
// Yes - force a user logoff on disconnect!
ExitWindowsEx(EWX_LOGOFF, 0);
}
}
// Delete the screen server
delete m_desktop;
m_desktop = NULL;
}
// Notify anyone interested of the change
//DoNotify(WM_SRV_CLIENT_DISCONNECT, 0, 0);
}
// NOTIFICATION HANDLING!
// Connect/disconnect notification
BOOL
vncServer::AddNotify(HWND hwnd)
{
omni_mutex_lock l(m_clientsLock);
// Add the window handle to the list
m_notifyList.push_front(hwnd);
return TRUE;
}
BOOL
vncServer::RemNotify(HWND hwnd)
{
omni_mutex_lock l(m_clientsLock);
// Remove the window handle from the list
vncNotifyList::iterator i;
for (i=m_notifyList.begin(); i!=m_notifyList.end(); i++)
{
if ((*i) == hwnd)
{
// Found the handle, so remove it
m_notifyList.erase(i);
return TRUE;
}
}
return FALSE;
}
// Send a notification message
void
vncServer::DoNotify(UINT message, WPARAM wparam, LPARAM lparam)
{
omni_mutex_lock l(m_clientsLock);
// Send the given message to all the notification windows
vncNotifyList::iterator i;
for (i=m_notifyList.begin(); i!=m_notifyList.end(); i++)
{
PostMessage((*i), message, wparam, lparam);
}
}
// Client->Desktop update signalling
void
vncServer::RequestUpdate()
{
omni_mutex_lock l(m_desktopLock);
if (m_desktop != NULL)
{
m_desktop->RequestUpdate();
}
}
// Update handling
void
vncServer::TriggerUpdate()
{
vncClientList::iterator i;
omni_mutex_lock l(m_clientsLock);
// Post this update to all the connected clients
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
// Post the update
GetClient(*i)->TriggerUpdate();
}
}
void
vncServer::UpdateRect(RECT &rect)
{
vncClientList::iterator i;
omni_mutex_lock l(m_clientsLock);
// Post this update to all the connected clients
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
// Post the update
GetClient(*i)->UpdateRect(rect);
}
}
void
vncServer::UpdateRegion(vncRegion &region)
{
vncClientList::iterator i;
omni_mutex_lock l(m_clientsLock);
// Post this update to all the connected clients
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
// Post the update
GetClient(*i)->UpdateRegion(region);
}
}
void
vncServer::CopyRect(RECT &dest, POINT &source)
{
vncClientList::iterator i;
omni_mutex_lock l(m_clientsLock);
// Post this update to all the connected clients
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
// Post the update
GetClient(*i)->CopyRect(dest, source);
}
}
void
vncServer::UpdateMouse()
{
vncClientList::iterator i;
omni_mutex_lock l(m_clientsLock);
// Post this mouse update to all the connected clients
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
// Post the update
GetClient(*i)->UpdateMouse();
}
}
void
vncServer::UpdateClipText(LPSTR text)
{
vncClientList::iterator i;
omni_mutex_lock l(m_clientsLock);
// Post this update to all the connected clients
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
// Post the update
GetClient(*i)->UpdateClipText(text);
}
}
void
vncServer::UpdatePalette()
{
vncClientList::iterator i;
omni_mutex_lock l(m_clientsLock);
// Post this update to all the connected clients
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
// Post the update
GetClient(*i)->UpdatePalette();
}
}
void
vncServer::UpdateLocalClipText(LPSTR text)
{
omni_mutex_lock l(m_desktopLock);
if (m_desktop != NULL)
m_desktop->SetClipText(text);
}
// Changing hook settings
void
vncServer::DontSetHooks(BOOL enable)
{
m_dont_set_hooks = enable;
if (m_desktop != NULL)
m_desktop->TryActivateHooks();
}
// Changing use driver settings
void
vncServer::DontUseDriver(BOOL enable)
{
m_dont_use_driver = enable;
}
void
vncServer::DriverDirectAccess(BOOL enable)
{
m_driver_direct_access_en = enable;
}
// Name and port number handling
void
vncServer::SetName(const char * name)
{
// Set the name of the desktop
if (m_name != NULL)
{
free(m_name);
m_name = NULL;
}
m_name = strdup(name);
}
void
vncServer::SetPorts(const UINT port_rfb, const UINT port_http)
{
if (m_port != port_rfb || m_port_http != port_http) {
// Set port numbers to use
m_port = port_rfb;
m_port_http = port_http;
// If there is already a listening socket then close and re-open it...
BOOL socketon = SockConnected();
SockConnect(FALSE);
if (socketon)
SockConnect(TRUE);
}
}
void
vncServer::SetPassword(BOOL activate, const char *passwd)
{
ResetPasswordsValidityInfo();
m_password_set = activate;
memcpy(m_password, passwd, MAXPWLEN);
}
BOOL
vncServer::GetPassword(char *passwd)
{
memcpy(passwd, m_password, MAXPWLEN);
return m_password_set;
}
void
vncServer::SetPasswordViewOnly(BOOL activate, const char *passwd)
{
ResetPasswordsValidityInfo();
m_password_viewonly_set = activate;
memcpy(m_password_viewonly, passwd, MAXPWLEN);
}
BOOL
vncServer::GetPasswordViewOnly(char *passwd)
{
memcpy(passwd, m_password_viewonly, MAXPWLEN);
return m_password_viewonly_set;
}
BOOL
vncServer::ValidPasswordsSet()
{
if (!m_valid_passwords_set_cached) {
m_valid_passwords_set = ValidPasswordsSet_nocache();
m_valid_passwords_set_cached = TRUE;
}
return m_valid_passwords_set;
}
BOOL
vncServer::ValidPasswordsSet_nocache()
{
char passwd1[MAXPWLEN];
char passwd2[MAXPWLEN];
BOOL set1 = GetPassword(passwd1);
BOOL set2 = GetPasswordViewOnly(passwd2);
if (!set1 && !set2)
return FALSE; // no passwords set, connections impossible
if (!AuthRequired())
return TRUE; // passwords may be empty, but we allow that
vncPasswd::ToText plain1(passwd1);
vncPasswd::ToText plain2(passwd2);
BOOL empty1 = !set1 || (strlen(plain1) == 0);
BOOL empty2 = !set2 || (strlen(plain2) == 0);
if (empty1 && empty2)
return FALSE; // both passwords empty or unset, not allowed
return TRUE; // at least one non-empty password
}
BOOL
vncServer::ValidPasswordsEmpty()
{
if (!m_valid_passwords_empty_cached) {
m_valid_passwords_empty = ValidPasswordsEmpty_nocache();
m_valid_passwords_empty_cached = TRUE;
}
return m_valid_passwords_empty;
}
BOOL
vncServer::ValidPasswordsEmpty_nocache()
{
if (AuthRequired())
return FALSE; // empty passwords disallowed, always fail
char passwd1[MAXPWLEN];
char passwd2[MAXPWLEN];
BOOL set1 = GetPassword(passwd1);
BOOL set2 = GetPasswordViewOnly(passwd2);
if (!set1 && !set2)
return FALSE; // no passwords set, connections impossible
vncPasswd::ToText plain1(passwd1);
vncPasswd::ToText plain2(passwd2);
BOOL empty1 = !set1 || (strlen(plain1) == 0);
BOOL empty2 = !set2 || (strlen(plain2) == 0);
if (empty1 && empty2)
return TRUE; // there are no passwords that are non-empty
return FALSE; // at least one non-empty password
}
// Remote input handling
void
vncServer::EnableRemoteInputs(BOOL enable)
{
m_enable_remote_inputs = enable;
}
BOOL vncServer::RemoteInputsEnabled()
{
return m_enable_remote_inputs;
}
// Local input handling
void
vncServer::DisableLocalInputs(BOOL disable)
{
if ( m_disable_local_inputs != disable )
{
m_disable_local_inputs = disable;
if ( AuthClientCount() != 0 )
m_desktop->SetLocalInputDisableHook(disable);
}
}
BOOL vncServer::LocalInputsDisabled()
{
return m_disable_local_inputs;
}
void vncServer::LocalInputPriority(BOOL disable)
{
if( m_local_input_priority != disable )
{
m_local_input_priority = disable;
m_remote_mouse = 0;
m_remote_keyboard = 0;
if ( AuthClientCount() != 0 )
m_desktop->SetLocalInputPriorityHook(disable);
}
}
// Socket connection handling
BOOL
vncServer::SockConnect(BOOL On)
{
// Are we being asked to switch socket connects on or off?
if (On)
{
// Is there a listening socket?
if (m_socketConn == NULL)
{
m_socketConn = new vncSockConnect();
if (m_socketConn == NULL)
return FALSE;
// Are we to use automatic port selection?
if (m_autoportselect)
{
BOOL ok = FALSE;
// Yes, so cycle through the ports, looking for a free one!
for (int i = 0; i < 99; i++)
{
m_port = DISPLAY_TO_PORT(i);
m_port_http = DISPLAY_TO_HPORT(i);
// Attempt to connect to the port
VSocket tempsock;
if (tempsock.Create())
{
if (!tempsock.Connect("localhost", m_port))
{
// Couldn't connect, so this port is probably usable!
if (m_socketConn->Init(this, m_port))
{
ok = TRUE;
break;
}
}
}
}
if (!ok)
{
delete m_socketConn;
m_socketConn = NULL;
return FALSE;
}
} else
{
// No autoportselect
if (!m_socketConn->Init(this, m_port))
{
delete m_socketConn;
m_socketConn = NULL;
return FALSE;
}
}
// Now let's start the HTTP connection stuff
/*if (m_httpConn == NULL && m_httpd_enabled && m_port_http != m_port) {
m_httpConn = new vncHTTPConnect;
if (m_httpConn != NULL) {
// Start up the HTTP server
if (!m_httpConn->Init(this, m_port_http,
m_httpd_params_enabled)) {
delete m_httpConn;
m_httpConn = NULL;
return FALSE;
}
}
}*/
}
}
else
{
// *** JNW - Trying to fix up a lock-up when the listening socket closes
#ifndef HORIZONLIVE
KillAuthClients();
KillUnauthClients();
WaitUntilAuthEmpty();
WaitUntilUnauthEmpty();
#endif
// Is there a listening socket?
if (m_socketConn != NULL)
{
// Close the socket
delete m_socketConn;
m_socketConn = NULL;
}
// Is there an HTTP socket active?
/*if (m_httpConn != NULL)
{
// Close the socket
delete m_httpConn;
m_httpConn = NULL;
}*/
}
return TRUE;
}
BOOL
vncServer::SockConnected()
{
return m_socketConn != NULL;
}
BOOL
vncServer::SetHttpdEnabled(BOOL enable_httpd, BOOL enable_params)
{
if (enable_httpd != m_httpd_enabled) {
m_httpd_enabled = enable_httpd;
m_httpd_params_enabled = enable_params;
BOOL socketConn = SockConnected();
SockConnect(FALSE);
SockConnect(socketConn);
} else {
if (enable_params != m_httpd_params_enabled) {
m_httpd_params_enabled = enable_params;
if (SockConnected()) {
SockConnect(FALSE);
SockConnect(TRUE);
}
}
}
return TRUE;
}
BOOL
vncServer::SetLoopbackOnly(BOOL loopbackOnly)
{
if (loopbackOnly != m_loopbackOnly)
{
m_loopbackOnly = loopbackOnly;
BOOL socketConn = SockConnected();
SockConnect(FALSE);
SockConnect(socketConn);
}
return TRUE;
}
BOOL
vncServer::LoopbackOnly()
{
return m_loopbackOnly;
}
BOOL
vncServer::SetDisableTrayIcon(BOOL disableTrayIcon)
{
if (disableTrayIcon != m_disableTrayIcon)
{
m_disableTrayIcon = disableTrayIcon;
}
return TRUE;
}
BOOL
vncServer::GetDisableTrayIcon()
{
return m_disableTrayIcon;
}
// CORBA connection handling
BOOL
vncServer::CORBAConnect(BOOL On)
{
// Are we being asked to switch CORBA connects on or off?
if (On)
{
// Is there a CORBA object?
if (m_corbaConn == NULL)
{
m_corbaConn = new vncCorbaConnect();
}
if (m_corbaConn == NULL)
return FALSE;
if (!m_corbaConn->Init(this))
{
delete m_corbaConn;
m_corbaConn = NULL;
return FALSE;
}
}
else
{
// Is there a listening socket?
if (m_corbaConn != NULL)
{
// Close the socket
delete m_corbaConn;
m_corbaConn = NULL;
}
}
return TRUE;
}
BOOL
vncServer::CORBAConnected()
{
return m_corbaConn != NULL;
}
void
vncServer::GetScreenInfo(int &width, int &height, int &depth)
{
rfbServerInitMsg scrinfo;
omni_mutex_lock l(m_desktopLock);
// Is a desktop object currently active?
if (m_desktop == NULL)
{
vncDesktop desktop;
// No, so create a dummy desktop and interrogate it
if (!desktop.Init(this))
{
scrinfo.framebufferWidth = 0;
scrinfo.framebufferHeight = 0;
scrinfo.format.bitsPerPixel = 0;
}
else
{
desktop.FillDisplayInfo(&scrinfo);
}
}
else
{
m_desktop->FillDisplayInfo(&scrinfo);
}
// Get the info from the scrinfo structure
width = m_shared_rect.right - m_shared_rect.left;
height = m_shared_rect.bottom - m_shared_rect.top;
depth = scrinfo.format.bitsPerPixel;
}
void
vncServer::SetAuthHosts(const char*hostlist) {
omni_mutex_lock l(m_clientsLock);
if (m_auth_hosts != 0)
free(m_auth_hosts);
if (hostlist == 0) {
m_auth_hosts = 0;
return;
}
m_auth_hosts = strdup(hostlist);
}
char*
vncServer::AuthHosts() {
omni_mutex_lock l(m_clientsLock);
if (m_auth_hosts == 0)
return strdup("");
else
return strdup(m_auth_hosts);
}
inline BOOL
MatchStringToTemplate(const char *addr, size_t addrlen,
const char *filtstr, size_t filtlen) {
if (filtlen == 0)
return 1;
if (addrlen < filtlen)
return 0;
for (size_t x = 0; x < filtlen; x++) {
if (addr[x] != filtstr[x])
return 0;
}
if ((addrlen > filtlen) && (addr[filtlen] != '.'))
return 0;
return 1;
}
vncServer::AcceptQueryReject
vncServer::VerifyHost(const char *hostname) {
if (ClientsDisabled())
return vncServer::aqrReject;
omni_mutex_lock l(m_clientsLock);
// -=- Is the specified host blacklisted?
vncServer::BlacklistEntry *current = m_blacklist;
vncServer::BlacklistEntry *previous = 0;
SYSTEMTIME systime;
FILETIME ftime;
LARGE_INTEGER now;
// Get the current time as a 64-bit value
GetSystemTime(&systime);
SystemTimeToFileTime(&systime, &ftime);
now.LowPart=ftime.dwLowDateTime;now.HighPart=ftime.dwHighDateTime;
now.QuadPart /= 10000000; // Convert it into seconds
while (current) {
// Has the blacklist entry timed out?
if ((now.QuadPart - current->_lastRefTime.QuadPart) > 0) {
// Yes. Is it a "blocked" entry?
if (current->_blocked) {
// Yes, so unblock it & re-set the reference time
current->_blocked = FALSE;
current->_lastRefTime.QuadPart = now.QuadPart + 10;
} else {
// No, so remove it
if (previous)
previous->_next = current->_next;
else
m_blacklist = current->_next;
vncServer::BlacklistEntry *next = current->_next;
free(current->_machineName);
delete current;
current = next;
continue;
}
}
// Is this the entry we're interested in?
if ((strcmp(current->_machineName, hostname) == 0) &&
(current->_blocked)) {
// Machine is blocked, so just reject it
return vncServer::aqrReject;
}
previous = current;
current = current->_next;
}
// Has a hostname been specified?
if (hostname == 0) {
return vncServer::aqrReject;
}
// Set the state machine into the correct mode & process the filter
enum vh_Mode {vh_ExpectDelimiter, vh_ExpectIncludeExclude, vh_ExpectPattern};
vh_Mode machineMode = vh_ExpectIncludeExclude;
vncServer::AcceptQueryReject verifiedHost = vncServer::aqrAccept;
vncServer::AcceptQueryReject patternType = vncServer::aqrReject;
UINT authHostsPos = 0;
UINT patternStart = 0;
size_t hostNameLen = strlen(hostname);
// Run through the auth hosts string until we hit the end
if (m_auth_hosts) {
while (1) {
// Which mode are we in?
switch (machineMode) {
// ExpectIncludeExclude - we should see a + or -.
case vh_ExpectIncludeExclude:
if (m_auth_hosts[authHostsPos] == '+') {
patternType = vncServer::aqrAccept;
patternStart = authHostsPos+1;
machineMode = vh_ExpectPattern;
} else if (m_auth_hosts[authHostsPos] == '-') {
patternType = vncServer::aqrReject;
patternStart = authHostsPos+1;
machineMode = vh_ExpectPattern;
} else if (m_auth_hosts[authHostsPos] == '?') {
patternType = vncServer::aqrQuery;
patternStart = authHostsPos+1;
machineMode = vh_ExpectPattern;
} else if (m_auth_hosts[authHostsPos] != '\0') {
machineMode = vh_ExpectDelimiter;
}
break;
// ExpectPattern - we expect to see a valid pattern
case vh_ExpectPattern:
// ExpectDelimiter - we're scanning for the next ':', skipping a pattern
case vh_ExpectDelimiter:
if ((m_auth_hosts[authHostsPos] == ':') ||
(m_auth_hosts[authHostsPos] == '\0')) {
if (machineMode == vh_ExpectPattern) {
if (patternStart == 0) {
} else {
// Process the match
if (MatchStringToTemplate(hostname, hostNameLen,
&(m_auth_hosts[patternStart]), authHostsPos-patternStart)) {
// The hostname matched - apply the include/exclude rule
verifiedHost = patternType;
}
}
}
// We now expect another + or -
machineMode = vh_ExpectIncludeExclude;
}
break;
}
// Have we hit the end of the pattern string?
if (m_auth_hosts[authHostsPos] == '\0')
break;
authHostsPos++;
}
}
return AdjustVerification(verifiedHost);
}
vncServer::AcceptQueryReject
vncServer::AdjustVerification(vncServer::AcceptQueryReject host)
{
vncServer::AcceptQueryReject verifiedHost = host;
// Based on the server's QuerySetting, adjust the verification result
switch (host) {
case vncServer::aqrAccept:
if (QuerySetting() >= 3)
verifiedHost = vncServer::aqrQuery;
break;
case vncServer::aqrQuery:
if (QuerySetting() <= 1)
verifiedHost = vncServer::aqrAccept;
else if (QuerySetting() == 4)
verifiedHost = vncServer::aqrReject;
break;
case vncServer::aqrReject:
if (QuerySetting() == 0)
verifiedHost = vncServer::aqrQuery;
break;
};
return verifiedHost;
}
void
vncServer::AddAuthHostsBlacklist(const char *machine) {
omni_mutex_lock l(m_clientsLock);
// -=- Is the specified host blacklisted?
vncServer::BlacklistEntry *current = m_blacklist;
// Get the current time as a 64-bit value
SYSTEMTIME systime;
FILETIME ftime;
LARGE_INTEGER now;
GetSystemTime(&systime);
SystemTimeToFileTime(&systime, &ftime);
now.LowPart=ftime.dwLowDateTime;now.HighPart=ftime.dwHighDateTime;
now.QuadPart /= 10000000; // Convert it into seconds
while (current) {
// Is this the entry we're interested in?
if (strcmp(current->_machineName, machine) == 0) {
// If the host is already blocked then ignore
if (current->_blocked)
return;
// Set the RefTime & failureCount
current->_lastRefTime.QuadPart = now.QuadPart + 10;
current->_failureCount++;
if (current->_failureCount > 5)
current->_blocked = TRUE;
return;
}
current = current->_next;
}
// Didn't find the entry
current = new vncServer::BlacklistEntry;
current->_blocked = FALSE;
current->_failureCount = 0;
current->_lastRefTime.QuadPart = now.QuadPart + 10;
current->_machineName = strdup(machine);
current->_next = m_blacklist;
m_blacklist = current;
}
void
vncServer::RemAuthHostsBlacklist(const char *machine) {
omni_mutex_lock l(m_clientsLock);
// -=- Is the specified host blacklisted?
vncServer::BlacklistEntry *current = m_blacklist;
vncServer::BlacklistEntry *previous = 0;
while (current) {
// Is this the entry we're interested in?
if (strcmp(current->_machineName, machine) == 0) {
if (previous)
previous->_next = current->_next;
else
m_blacklist = current->_next;
vncServer::BlacklistEntry *next = current->_next;
free (current->_machineName);
delete current;
current = next;
continue;
}
previous = current;
current = current->_next;
}
}
void
vncServer::SetWindowShared(HWND hWnd)
{
m_hwndShared=hWnd;
}
void vncServer::SetMatchSizeFields(int left,int top,int right,int bottom)
{
RECT trect = GetScreenRect();
/* if ( right - left < 32 )
right = left + 32;
if ( bottom - top < 32)
bottom = top + 32 ;*/
if( right > trect.right )
right = trect.right;
if( bottom > trect.bottom )
bottom = trect.bottom;
if( left < trect.left)
left = trect.left;
if( top < trect.top)
top = trect.top;
m_screenarea_rect.left=left;
m_screenarea_rect.top=top;
m_screenarea_rect.bottom=bottom;
m_screenarea_rect.right=right;
}
void
vncServer::SetKeyboardCounter(int count)
{
omni_mutex_lock l(m_clientsLock);
if (LocalInputPriority() && vncService::IsWin95())
{
m_remote_keyboard += count;
if (count == 0)
m_remote_keyboard = 0;
}
}
void
vncServer::SetMouseCounter(int count, POINT &cursor_pos, BOOL mousemove)
{
if( (mousemove) && ( abs (m_cursor_pos.x - cursor_pos.x)==0
&& abs (m_cursor_pos.y - cursor_pos.y)==0 ) )
return;
omni_mutex_lock l(m_clientsLock);
if (LocalInputPriority() && vncService::IsWin95())
{
m_remote_mouse += count;
if (count == 0)
m_remote_mouse = 0;
m_cursor_pos.x = cursor_pos.x;
m_cursor_pos.y = cursor_pos.y;
}
}
void
vncServer::SetNewFBSize(BOOL sendnewfb)
{
vncClientList::iterator i;
omni_mutex_lock l(m_clientsLock);
// Post new framebuffer size update to all the connected clients
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
// Post the update
GetClient(*i)->SetNewFBSize( sendnewfb);
}
}
BOOL
vncServer::FullRgnRequested()
{
vncClientList::iterator i;
omni_mutex_lock l(m_clientsLock);
// Iterate over the authorised clients
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
if (GetClient(*i)->FullRgnRequested())
return TRUE;
}
return FALSE;
}
BOOL
vncServer::IncrRgnRequested()
{
vncClientList::iterator i;
omni_mutex_lock l(m_clientsLock);
// Iterate over the authorised clients
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
if (GetClient(*i)->IncrRgnRequested())
return TRUE;
}
return FALSE;
}
void
vncServer::UpdateLocalFormat()
{
vncClientList::iterator i;
omni_mutex_lock l(m_clientsLock);
// Iterate over the authorised clients
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
GetClient(*i)->UpdateLocalFormat();
}
return;
}
void
vncServer::SetPollingCycle(UINT msec)
{
if (m_polling_cycle != msec && msec > 10) {
m_polling_cycle = msec;
PollingCycleChanged(true);
}
}
BOOL
vncServer::checkPointer(vncClient *pClient)
{
vncClientList::iterator i;
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
if (GetClient(*i) == pClient) return TRUE;
}
return FALSE;
}
BOOL
vncServer::DriverActive() {
return (m_desktop != NULL) ? m_desktop->DriverActive() : FALSE;
}
typedef HMONITOR (WINAPI* pMonitorFromPoint)(POINT,DWORD);
typedef BOOL (WINAPI* pGetMonitorInfo)(HMONITOR,LPMONITORINFO);
BOOL vncServer::SetShareMonitorFromPoint(POINT pt)
{
HINSTANCE hInstUser32 = LoadLibrary("User32.DLL");
if (!hInstUser32) return FALSE;
pMonitorFromPoint pMFP = (pMonitorFromPoint)GetProcAddress(hInstUser32, "MonitorFromPoint");
pGetMonitorInfo pGMI = (pGetMonitorInfo)GetProcAddress(hInstUser32, "GetMonitorInfoA");
if (!pMFP || !pGMI)
{
FreeLibrary(hInstUser32);
return FALSE;
}
HMONITOR hm = pMFP(pt, MONITOR_DEFAULTTONEAREST);
if (!hm)
{
FreeLibrary(hInstUser32);
return FALSE;
}
MONITORINFO moninfo;
moninfo.cbSize = sizeof(moninfo);
if (!pGMI(hm, &moninfo))
{
FreeLibrary(hInstUser32);
return FALSE;
}
FullScreen(FALSE);
WindowShared(FALSE);
ScreenAreaShared(TRUE);
PrimaryDisplayOnlyShared(FALSE);
SetMatchSizeFields(
moninfo.rcMonitor.left,
moninfo.rcMonitor.top,
moninfo.rcMonitor.right,
moninfo.rcMonitor.bottom);
FreeLibrary(hInstUser32);
return TRUE;
}