📄 vncclient.cpp
字号:
// Send updates to the client - this implicitly clears
// the supplied update tracker
if (m_client->SendUpdate(update)) {
updates_sent++;
clipregion.clear();
}
yield();
}
vnclog.Print(LL_INTINFO, VNCLOG("stopping update thread\n"));
vnclog.Print(LL_INTERR, "client sent %lu updates\n", updates_sent);
return 0;
}
// vncClient thread class
class vncClientThread : public omni_thread
{
public:
// Init
virtual BOOL Init(vncClient *client,
vncServer *server,
VSocket *socket,
BOOL auth,
BOOL shared);
// Sub-Init routines
virtual BOOL InitVersion();
virtual BOOL InitAuthenticate();
// The main thread function
virtual void run(void *arg);
protected:
virtual ~vncClientThread();
// Fields
protected:
VSocket *m_socket;
vncServer *m_server;
vncClient *m_client;
BOOL m_auth;
BOOL m_shared;
BOOL m_ms_logon;
};
vncClientThread::~vncClientThread()
{
// If we have a client object then delete it
if (m_client != NULL)
delete m_client;
}
BOOL
vncClientThread::Init(vncClient *client, vncServer *server, VSocket *socket, BOOL auth, BOOL shared)
{
// Save the server pointer and window handle
m_server = server;
m_socket = socket;
m_client = client;
m_auth = auth;
m_shared = shared;
// Start the thread
start();
return TRUE;
}
BOOL
vncClientThread::InitVersion()
{
rfbProtocolVersionMsg protocol_ver;
protocol_ver[12] = 0;
if (strcmp(m_client->ProtocolVersionMsg,"0.0.0.0")==NULL)
{
// Generate the server's protocol version
rfbProtocolVersionMsg protocolMsg;
sprintf((char *)protocolMsg,
rfbProtocolVersionFormat,
rfbProtocolMajorVersion,
rfbProtocolMinorVersion + (m_server->MSLogonRequired() ? 0 : 2)); // 4: mslogon+FT,
// 6: VNClogon+FT
// Send the protocol message
m_socket->SetTimeout(0);
if (!m_socket->SendExact((char *)&protocolMsg, sz_rfbProtocolVersionMsg))
return FALSE;
// Now, get the client's protocol version
if (!m_socket->ReadExact((char *)&protocol_ver, sz_rfbProtocolVersionMsg))
{
return FALSE;
}
}
else memcpy(protocol_ver,m_client->ProtocolVersionMsg,sz_rfbProtocolVersionMsg);
// Check viewer's the protocol version
int major, minor;
sscanf((char *)&protocol_ver, rfbProtocolVersionFormat, &major, &minor);
if (major != rfbProtocolMajorVersion)
return FALSE;
// TODO: Maybe change this UltraVNC specific minor value because
// TightVNC viewer uses minor = 5 ...
// For now:
// UltraViewer always sends minor = 4 (sf@2005: or 6, as it returns the minor version received from the server)
// UltraServer sends minor = 4 or minor = 6
// m_ms_logon = false; // For all non-UltraVNC logon compatible viewers
m_ms_logon = m_server->MSLogonRequired();
vnclog.Print(LL_INTINFO, VNCLOG("m_ms_logon set to %s"), m_ms_logon ? "true" : "false");
if (minor == 4 || minor == 6) m_client->SetUltraViewer(true); else m_client->SetUltraViewer(false); // sf@2005 - Fix Open TextChat from server bug
return TRUE;
}
BOOL
vncClientThread::InitAuthenticate()
{
vnclog.Print(LL_INTINFO, "Entered InitAuthenticate");
// Retrieve the local password
char password[MAXPWLEN];
char passwordMs[MAXMSPWLEN];
m_server->GetPassword(password);
vncPasswd::ToText plain(password);
// Verify the peer host name against the AuthHosts string
vncServer::AcceptQueryReject verified;
if (m_auth) {
verified = vncServer::aqrAccept;
} else {
verified = m_server->VerifyHost(m_socket->GetPeerName());
}
// If necessary, query the connection with a timed dialog
char username[UNLEN+1];
if (!vncService::CurrentUser(username, sizeof(username))) return false;
if (strcmp(username, "") != 0)
if (verified == vncServer::aqrQuery) {
vncAcceptDialog *acceptDlg = new vncAcceptDialog(m_server->QueryTimeout(),m_server->QueryAccept(), m_socket->GetPeerName());
if (acceptDlg == NULL)
{
if (m_server->QueryAccept()==1)
{
verified = vncServer::aqrAccept;
}
else
{
verified = vncServer::aqrReject;
}
}
else
{
if ( !(acceptDlg->DoDialog()) ) verified = vncServer::aqrReject;
}
}
if (verified == vncServer::aqrReject) {
CARD32 auth_val = Swap32IfLE(rfbConnFailed);
char *errmsg = "Your connection has been rejected.";
CARD32 errlen = Swap32IfLE(strlen(errmsg));
if (!m_socket->SendExact((char *)&auth_val, sizeof(auth_val)))
return FALSE;
if (!m_socket->SendExact((char *)&errlen, sizeof(errlen)))
return FALSE;
m_socket->SendExact(errmsg, strlen(errmsg));
return FALSE;
}
// By default we disallow passwordless workstations!
if ((strlen(plain) == 0) && m_server->AuthRequired())
{
vnclog.Print(LL_CONNERR, VNCLOG("no password specified for server - client rejected\n"));
// Send an error message to the client
CARD32 auth_val = Swap32IfLE(rfbConnFailed);
char *errmsg =
"This server does not have a valid password enabled. "
"Until a password is set, incoming connections cannot be accepted.";
CARD32 errlen = Swap32IfLE(strlen(errmsg));
if (!m_socket->SendExact((char *)&auth_val, sizeof(auth_val)))
return FALSE;
if (!m_socket->SendExact((char *)&errlen, sizeof(errlen)))
return FALSE;
m_socket->SendExact(errmsg, strlen(errmsg));
return FALSE;
}
// By default we filter out local loop connections, because they're pointless
if (!m_server->LoopbackOk())
{
char *localname = strdup(m_socket->GetSockName());
char *remotename = strdup(m_socket->GetPeerName());
// Check that the local & remote names are different!
if ((localname != NULL) && (remotename != NULL))
{
BOOL ok = strcmp(localname, remotename) != 0;
if (localname != NULL)
free(localname);
if (remotename != NULL)
free(remotename);
if (!ok)
{
vnclog.Print(LL_CONNERR, VNCLOG("loopback connection attempted - client rejected\n"));
// Send an error message to the client
CARD32 auth_val = Swap32IfLE(rfbConnFailed);
char *errmsg = "Local loop-back connections are disabled.";
CARD32 errlen = Swap32IfLE(strlen(errmsg));
if (!m_socket->SendExact((char *)&auth_val, sizeof(auth_val)))
return FALSE;
if (!m_socket->SendExact((char *)&errlen, sizeof(errlen)))
return FALSE;
m_socket->SendExact(errmsg, strlen(errmsg));
return FALSE;
}
}
}
else
{
char *localname = strdup(m_socket->GetSockName());
char *remotename = strdup(m_socket->GetPeerName());
// Check that the local & remote names are different!
if ((localname != NULL) && (remotename != NULL))
{
BOOL ok = strcmp(localname, remotename) != 0;
if (localname != NULL)
free(localname);
if (remotename != NULL)
free(remotename);
if (!ok)
{
vnclog.Print(LL_CONNERR, VNCLOG("loopback connection attempted - client accepted\n"));
m_client->m_IsLoopback=true;
}
}
}
// Authenticate the connection, if required
if (m_auth || (strlen(plain) == 0))
{
// Send no-auth-required message
CARD32 auth_val = Swap32IfLE(rfbNoAuth);
if (!m_socket->SendExact((char *)&auth_val, sizeof(auth_val)))
return FALSE;
}
else
{
// Send auth-required message
CARD32 auth_val = Swap32IfLE(rfbVncAuth);
if (!m_socket->SendExact((char *)&auth_val, sizeof(auth_val)))
return FALSE;
BOOL auth_ok = TRUE;
{
/*
// sf@2002 - DSMPlugin
// Use Plugin only from this point for the moment
if (m_server->GetDSMPluginPointer()->IsEnabled())
{
m_socket->EnableUsePlugin(true);
// TODO: Make a more secured challenge (with time stamp)
}
*/
// Now create a 16-byte challenge
char challenge[16];
char challengems[64];
char response[16];
char responsems[64];
char *plainmsPasswd;
char user[256];
char domain[256];
vncRandomBytes((BYTE *)&challenge);
vncRandomBytesMs((BYTE *)&challengems);
// Send the challenge to the client
// m_ms_logon = false;
if (m_ms_logon)
{
vnclog.Print(LL_INTINFO, "MS-Logon authentication");
if (!m_socket->SendExact(challengems, sizeof(challengems)))
return FALSE;
if (!m_socket->SendExact(challenge, sizeof(challenge)))
return FALSE;
if (!m_socket->ReadExact(user, sizeof(char)*256))
return FALSE;
if (!m_socket->ReadExact(domain, sizeof(char)*256))
return FALSE;
// Read the response
if (!m_socket->ReadExact(responsems, sizeof(responsems)))
return FALSE;
if (!m_socket->ReadExact(response, sizeof(response)))
return FALSE;
// TODO: Improve this...
for (int i = 0; i < 32 ;i++)
{
passwordMs[i] = challengems[i]^responsems[i];
}
// REM: Instead of the fixedkey, we could use VNC password
// -> the user needs to enter the VNC password on viewer's side.
plainmsPasswd = vncDecryptPasswdMs((char *)passwordMs);
// We let it as is right now for testing purpose.
if (strlen(user) == 0 && !m_server->MSLogonRequired())
{
vnclog.Print(LL_INTINFO, "No user specified, mslogon not required");
vncEncryptBytes((BYTE *)&challenge, plain);
// Compare them to the response
for (int i=0; i<sizeof(challenge); i++)
{
if (challenge[i] != response[i])
{
auth_ok = FALSE;
break;
}
}
}
else
{
vnclog.Print(LL_INTINFO, "User specified or mslogon required");
int result=CheckUserGroupPasswordUni(user,plainmsPasswd,m_client->GetClientName());
vnclog.Print(LL_INTINFO, "CheckUserGroupPasswordUni result=%i", result);
if (result==0) auth_ok = FALSE;
if (result==2)
{
m_client->EnableKeyboard(false);
m_client->EnablePointer(false);
}
}
if (plainmsPasswd) free(plainmsPasswd);
plainmsPasswd=NULL;
}
else
{
vnclog.Print(LL_INTINFO, "password authentication");
if (!m_socket->SendExact(challenge, sizeof(challenge)))
return FALSE;
// Read the response
if (!m_socket->ReadExact(response, sizeof(response)))
return FALSE;
// Encrypt the challenge bytes
vncEncryptBytes((BYTE *)&challenge, plain);
// Compare them to the response
for (int i=0; i<sizeof(challenge); i++)
{
if (challenge[i] != response[i])
{
auth_ok = FALSE;
break;
}
}
}
}
// Did the authentication work?
CARD32 authmsg;
if (!auth_ok)
{
vnclog.Print(LL_CONNERR, VNCLOG("authentication failed\n"));
//////////////////
// LOG it also in the event
//////////////////
{
typedef BOOL (*LogeventFn)(char *machine);
LogeventFn Logevent = 0;
char szCurrentDir[MAX_PATH];
if (GetModuleFileName(NULL, szCurrentDir, MAX_PATH))
{
char* p = strrchr(szCurrentDir, '\\');
*p = '\0';
strcat (szCurrentDir,"\\logging.dll");
}
HMODULE hModule = LoadLibrary(szCurrentDir);
if (hModule)
{
BOOL result=false;
Logevent = (LogeventFn) GetProcAddress( hModule, "LOGFAILED" );
Logevent((char *)m_client->GetClientName());
FreeLibrary(hModule);
}
}
authmsg = Swap32IfLE(rfbVncAuthFailed);
m_socket->SendExact((char *)&authmsg, sizeof(authmsg));
return FALSE;
}
else
{
// Tell the client we're ok
authmsg = Swap32IfLE(rfbVncAuthOK);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -