📄 clientconnection.cpp
字号:
WriteExact(pv, sz_rfbProtocolVersionMsg);
if (m_connDlg != NULL)
m_connDlg->SetStatus("Protocol version negotiated");
vnclog.Print(0, _T("Connected to RFB server, using protocol version 3.%d\n"),
m_minorVersion);
}
//
// Negotiate authentication scheme and authenticate if necessary
//
void ClientConnection::PerformAuthentication()
{
int secType;
if (m_minorVersion >= 7) {
secType = SelectSecurityType();
} else {
secType = ReadSecurityType();
}
switch (secType) {
case rfbSecTypeNone:
Authenticate(rfbAuthNone);
m_authScheme = rfbAuthNone;
break;
case rfbSecTypeVncAuth:
Authenticate(rfbAuthVNC);
m_authScheme = rfbAuthVNC;
break;
case rfbSecTypeTight:
m_tightVncProtocol = true;
InitCapabilities();
SetupTunneling();
PerformAuthenticationTight();
break;
default: // should never happen
vnclog.Print(0, _T("Internal error: Invalid security type\n"));
throw ErrorException("Internal error: Invalid security type");
}
}
//
// Read security type from the server (protocol 3.3)
//
int ClientConnection::ReadSecurityType()
{
// Read the authentication scheme.
CARD32 secType;
ReadExact((char *)&secType, sizeof(secType));
secType = Swap32IfLE(secType);
if (secType == rfbSecTypeInvalid)
throw WarningException(ReadFailureReason());
if (secType != rfbSecTypeNone && secType != rfbSecTypeVncAuth) {
vnclog.Print(0, _T("Unknown security type from RFB server: %d\n"),
(int)secType);
throw ErrorException("Unknown security type requested!");
}
if (m_connDlg != NULL)
m_connDlg->SetStatus("Security type received");
return (int)secType;
}
//
// Select security type from the server's list (protocol 3.7 and above)
//
int ClientConnection::SelectSecurityType()
{
// Read the list of secutiry types.
CARD8 nSecTypes;
ReadExact((char *)&nSecTypes, sizeof(nSecTypes));
if (nSecTypes == 0)
throw WarningException(ReadFailureReason());
char *secTypeNames[] = {"None", "VncAuth"};
CARD8 knownSecTypes[] = {rfbSecTypeNone, rfbSecTypeVncAuth};
int nKnownSecTypes = sizeof(knownSecTypes);
CARD8 *secTypes = new CARD8[nSecTypes];
ReadExact((char *)secTypes, nSecTypes);
CARD8 secType = rfbSecTypeInvalid;
if (m_connDlg != NULL)
m_connDlg->SetStatus("List of security types received");
// Find out if the server supports TightVNC protocol extensions
int j;
for (j = 0; j < (int)nSecTypes; j++) {
if (secTypes[j] == rfbSecTypeTight) {
secType = rfbSecTypeTight;
WriteExact((char *)&secType, sizeof(secType));
if (m_connDlg != NULL)
m_connDlg->SetStatus("TightVNC protocol extensions enabled");
vnclog.Print(8, _T("Enabling TightVNC protocol extensions\n"));
return rfbSecTypeTight;
}
}
// Find first supported security type
for (j = 0; j < (int)nSecTypes; j++) {
for (int i = 0; i < nKnownSecTypes; i++) {
if (secTypes[j] == knownSecTypes[i]) {
secType = secTypes[j];
WriteExact((char *)&secType, sizeof(secType));
if (m_connDlg != NULL)
m_connDlg->SetStatus("Security type requested");
vnclog.Print(8, _T("Choosing security type %s(%d)\n"),
secTypeNames[i], (int)secType);
break;
}
}
if (secType != rfbSecTypeInvalid) break;
}
if (secType == rfbSecTypeInvalid) {
vnclog.Print(0, _T("Server did not offer supported security type\n"));
throw ErrorException("Server did not offer supported security type!");
}
return (int)secType;
}
//
// Setup tunneling (protocol 3.7t, 3.8t)
//
void ClientConnection::SetupTunneling()
{
rfbTunnelingCapsMsg caps;
ReadExact((char *)&caps, sz_rfbTunnelingCapsMsg);
caps.nTunnelTypes = Swap32IfLE(caps.nTunnelTypes);
if (caps.nTunnelTypes) {
ReadCapabilityList(&m_tunnelCaps, caps.nTunnelTypes);
if (m_connDlg != NULL)
m_connDlg->SetStatus("List of tunneling capabilities received");
// We cannot do tunneling yet.
CARD32 tunnelType = Swap32IfLE(rfbNoTunneling);
WriteExact((char *)&tunnelType, sizeof(tunnelType));
if (m_connDlg != NULL)
m_connDlg->SetStatus("Tunneling type requested");
}
}
//
// Negotiate authentication scheme (protocol 3.7t, 3.8t)
//
void ClientConnection::PerformAuthenticationTight()
{
rfbAuthenticationCapsMsg caps;
ReadExact((char *)&caps, sz_rfbAuthenticationCapsMsg);
caps.nAuthTypes = Swap32IfLE(caps.nAuthTypes);
if (m_connDlg != NULL)
m_connDlg->SetStatus("Header of authentication capability list received");
if (!caps.nAuthTypes) {
vnclog.Print(0, _T("No authentication needed\n"));
if (m_connDlg != NULL)
m_connDlg->SetStatus("No authentication needed");
Authenticate(rfbAuthNone);
m_authScheme = rfbAuthNone;
} else {
ReadCapabilityList(&m_authCaps, caps.nAuthTypes);
if (m_connDlg != NULL)
m_connDlg->SetStatus("Authentication capability list received");
if (!m_authCaps.NumEnabled()) {
vnclog.Print(0, _T("No suitable authentication schemes offered by the server\n"));
throw ErrorException("No suitable authentication schemes offered by the server");
}
// Use server's preferred authentication scheme.
CARD32 authScheme = m_authCaps.GetByOrder(0);
authScheme = Swap32IfLE(authScheme);
WriteExact((char *)&authScheme, sizeof(authScheme));
authScheme = Swap32IfLE(authScheme); // convert it back
if (m_connDlg != NULL)
m_connDlg->SetStatus("Authentication scheme requested");
Authenticate(authScheme);
m_authScheme = authScheme;
}
}
// The definition of a function implementing some authentication scheme.
// For an example, see ClientConnection::AuthenticateVNC, below.
typedef bool (ClientConnection::*AuthFunc)(char *, int);
// A wrapper function for different authentication schemes.
void ClientConnection::Authenticate(CARD32 authScheme)
{
AuthFunc authFuncPtr;
// Uncomment this if the "Connecting..." dialog box should be
// closed prior to authentication.
/***
if (m_connDlg != NULL) {
delete m_connDlg;
m_connDlg = NULL;
}
***/
switch(authScheme) {
case rfbAuthNone:
authFuncPtr = &ClientConnection::AuthenticateNone;
break;
case rfbAuthVNC:
authFuncPtr = &ClientConnection::AuthenticateVNC;
break;
default:
vnclog.Print(0, _T("Unknown authentication scheme: %d\n"),
(int)authScheme);
throw ErrorException("Unknown authentication scheme!");
}
vnclog.Print(0, _T("Authentication scheme: %s\n"),
m_authCaps.GetDescription(authScheme));
const int errorMsgSize = 256;
CheckBufferSize(errorMsgSize);
char *errorMsg = m_netbuf;
bool wasError = !(this->*authFuncPtr)(errorMsg, errorMsgSize);
// Report authentication error.
if (wasError) {
vnclog.Print(0, _T("%s\n"), errorMsg);
if (m_connDlg != NULL)
m_connDlg->SetStatus("Error during authentication");
throw AuthException(errorMsg);
}
CARD32 authResult;
if (authScheme == rfbAuthNone && m_minorVersion < 8) {
// In protocol versions prior to 3.8, "no authentication" is a
// special case - no "security result" is sent by the server.
authResult = rfbAuthOK;
} else {
ReadExact((char *) &authResult, 4);
authResult = Swap32IfLE(authResult);
}
switch (authResult) {
case rfbAuthOK:
if (m_connDlg != NULL)
m_connDlg->SetStatus("Authentication successful");
vnclog.Print(0, _T("Authentication successful\n"));
return;
case rfbAuthFailed:
if (m_minorVersion >= 8) {
errorMsg = ReadFailureReason();
} else {
errorMsg = "Authentication failure";
}
break;
case rfbAuthTooMany:
errorMsg = "Authentication failure, too many tries";
break;
default:
_snprintf(m_netbuf, 256, "Unknown authentication result (%d)",
(int)authResult);
errorMsg = m_netbuf;
break;
}
// Report authentication failure.
vnclog.Print(0, _T("%s\n"), errorMsg);
if (m_connDlg != NULL)
m_connDlg->SetStatus(errorMsg);
throw AuthException(errorMsg);
}
// "Null" authentication.
bool ClientConnection::AuthenticateNone(char *errBuf, int errBufSize)
{
return true;
}
// The standard VNC authentication.
//
// An authentication function should return false on error and true if
// the authentication process was successful. Note that returning true
// does not mean that authentication was passed by the server, the
// server's result will be received and analyzed later.
// If false is returned, then a text error message should be copied
// to errorBuf[], no more than errBufSize bytes should be copied into
// that buffer.
bool ClientConnection::AuthenticateVNC(char *errBuf, int errBufSize)
{
CARD8 challenge[CHALLENGESIZE];
ReadExact((char *)challenge, CHALLENGESIZE);
char passwd[MAXPWLEN + 1];
// Was the password already specified in a config file?
if (strlen((const char *) m_encPasswd) > 0) {
char *pw = vncDecryptPasswd(m_encPasswd);
strcpy(passwd, pw);
free(pw);
} else {
LoginAuthDialog ad(m_opts.m_display, "Standard VNC Authentication");
ad.DoDialog();
#ifndef UNDER_CE
strncpy(passwd, ad.m_passwd, MAXPWLEN);
passwd[MAXPWLEN]= '\0';
#else
// FIXME: Move wide-character translations to a separate class
int origlen = _tcslen(ad.m_passwd);
int newlen = WideCharToMultiByte(
CP_ACP, // code page
0, // performance and mapping flags
ad.m_passwd, // address of wide-character string
origlen, // number of characters in string
passwd, // address of buffer for new string
255, // size of buffer
NULL, NULL);
passwd[newlen]= '\0';
#endif
if (strlen(passwd) == 0) {
_snprintf(errBuf, errBufSize, "Empty password");
return false;
}
if (strlen(passwd) > 8) {
passwd[8] = '\0';
}
vncEncryptPasswd(m_encPasswd, passwd);
}
vncEncryptBytes(challenge, passwd);
/* Lose the plain-text password from memory */
memset(passwd, 0, strlen(passwd));
WriteExact((char *) challenge, CHALLENGESIZE);
return true;
}
void ClientConnection::SendClientInit()
{
rfbClientInitMsg ci;
ci.shared = m_opts.m_Shared;
WriteExact((char *)&ci, sz_rfbClientInitMsg);
if (m_connDlg != NULL)
m_connDlg->SetStatus("Client initialization message sent");
}
void ClientConnection::ReadServerInit()
{
ReadExact((char *)&m_si, sz_rfbServerInitMsg);
if (m_connDlg != NULL)
m_connDlg->SetStatus("Server initialization message received");
m_si.framebufferWidth = Swap16IfLE(m_si.framebufferWidth);
m_si.framebufferHeight = Swap16IfLE(m_si.framebufferHeight);
m_si.format.redMax = Swap16IfLE(m_si.format.redMax);
m_si.format.greenMax = Swap16IfLE(m_si.format.greenMax);
m_si.format.blueMax = Swap16IfLE(m_si.format.blueMax);
m_si.nameLength = Swap32IfLE(m_si.nameLength);
m_desktopName = new TCHAR[m_si.nameLength + 2];
#ifdef UNDER_CE
char *deskNameBuf = new char[m_si.nameLength + 2];
ReadString(deskNameBuf, m_si.nameLength);
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED,
deskNameBuf, m_si.nameLength,
m_desktopName, m_si.nameLength+1);
delete deskNameBuf;
#else
ReadString(m_desktopName, m_si.nameLength);
#endif
SetWindowText(m_hwnd1, m_desktopName);
vnclog.Print(0, _T("Desktop name \"%s\"\n"),m_desktopName);
vnclog.Print(1, _T("Geometry %d x %d depth %d\n"),
m_si.framebufferWidth, m_si.framebufferHeight, m_si.format.depth );
SetWindowText(m_hwnd1, m_desktopName);
SizeWindow(true);
}
//
// In protocols 3.7t/3.8t, the server informs us about supported
// protocol messages and encodings. Here we read this information.
//
void ClientConnection::ReadInteractionCaps()
{
// Read the counts of list items following
rfbInteractionCapsMsg intr_caps;
ReadExact((char *)&intr_caps, sz_rfbInteractionCapsMsg);
intr_caps.nServerMessageTypes = Swap16IfLE(intr_caps.nServerMessageTypes);
intr_caps.nClientMessageTypes = Swap16IfLE(intr_caps.nClientMessageTypes);
intr_caps.nEncodingTypes = Swap16IfLE(intr_caps.nEncodingTypes);
if (m_connDlg != NULL)
m_connDlg->SetStatus("Interaction capability list header received");
// Read the lists of server- and client-initiated messages
ReadCapabilityList(&m_serverMsgCaps, intr_caps.nServerMessageTypes);
ReadCapabilityList(&m_clientMsgCaps, intr_caps.nClientMessageTypes);
ReadCapabilityList(&m_encodingCaps, intr_caps.nEncodingTypes);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -