Commit 50df3f81 authored by Paul Tvete's avatar Paul Tvete
Browse files

Proper password support

Make it a settable property
parent 5473a0a3
......@@ -123,6 +123,8 @@ void QVncItem::createServer()
QSize s(width(), height());// = newGeometry.size().toSize();
qDebug() << "Creating VNC server with size" << s << "on port" << m_vncPort;
m_vncServer = new QVncServer(s, QImage::Format_ARGB32, m_vncPort);
m_vncServer->setPassword(password());
connect(this, &QVncItem::passwordChanged, m_vncServer, &QVncServer::setPassword);
connect(m_vncServer, &QVncServer::isConnectedChanged, this, &QVncItem::setConnectionActive);
connect(m_vncServer, &QVncServer::mouseEventReceived, this, [this](
......@@ -386,4 +388,18 @@ void QVncItem::setVncPort(int newVncPort)
emit vncPortChanged();
}
const QByteArray &QVncItem::password() const
{
return m_password;
}
void QVncItem::setPassword(const QByteArray &newPassword)
{
if (m_password == newPassword)
return;
m_password = newPassword;
emit passwordChanged(newPassword);
}
QT_END_NAMESPACE
......@@ -17,6 +17,7 @@ class QVncItem : public QQuickItem
Q_PROPERTY(bool remoteInputEnabled READ remoteInputEnabled WRITE setRemoteInputEnabled NOTIFY remoteInputEnabledChanged)
Q_PROPERTY(bool connectionActive READ connectionActive NOTIFY connectionActiveChanged)
Q_PROPERTY(int vncPort READ vncPort WRITE setVncPort NOTIFY vncPortChanged)
Q_PROPERTY(QByteArray password READ password WRITE setPassword NOTIFY passwordChanged)
QML_NAMED_ELEMENT(VncItem)
public:
......@@ -36,6 +37,9 @@ public:
int vncPort() const;
void setVncPort(int newVncPort);
const QByteArray &password() const;
void setPassword(const QByteArray &newPassword);
public Q_SLOTS:
void handleMouse(QMouseEvent *mev);
void handleKey(QKeyEvent *kev);
......@@ -49,6 +53,8 @@ Q_SIGNALS:
void vncPortChanged();
void passwordChanged(QByteArray newPassword);
protected:
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *data) override;
......@@ -83,6 +89,7 @@ private:
QElapsedTimer m_frameTimer;
int m_frameCount = 0;
int m_grabCount = 0;
QByteArray m_password;
};
QT_END_NAMESPACE
......
......@@ -241,29 +241,11 @@ public:
int QVncClient::sharedButtonState = Qt::NoButton;
static inline QByteArray reverseBits(const char *bytes, int len)
{
auto rev = [](const uchar b) -> uchar {
return ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
};
QByteArray result;
result.reserve(len);
for (int i = 0; i < len; ++i)
result += rev(bytes[i]);
qDebug() << "Twiddle:" << result;
return result;
}
QVncClient::QVncClient(QVncServer *server)
: QObject(nullptr)
, m_server(server)
, m_supportDesktopSize(false)
{
const char pwd[8]{'A', 'B', 'C', 'D', 0}; //Just testing...
m_passwordTest = reverseBits(pwd, sizeof(pwd));
}
void QVncClient::initialize(qintptr handle)
......@@ -319,6 +301,11 @@ void QVncClient::setDirty(const QRegion &region)
scheduleUpdate();
}
void QVncClient::setPassword(QByteArray password)
{
m_password = password;
}
void QVncClient::scheduleUpdate()
{
if (!m_updatePending) {
......@@ -545,17 +532,25 @@ int QVncClient::dirtyMapCount() const
}
#ifdef LIBTOMCRYPT_FOUND
static QByteArray desHash(const QByteArray &data, const QByteArray &passwd)
static QByteArray desHash(const QByteArray &data, const QByteArray &password)
{
Q_ASSERT(passwd.length() == 8 && data.length() == 16);
Q_ASSERT(data.length() == 16);
// http://graphics.stanford.edu/~seander/bithacks.html
auto reverseBits = [](const uchar b) -> uchar {
return ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
};
auto getData = [](const QByteArray &ba) -> const unsigned char * {return reinterpret_cast<const unsigned char*>(ba.constData()); };
uchar passwd[8] {};
int len = qMin(8, password.length());
for (int i = 0; i < len; ++i)
passwd[i] = reverseBits(password[i]);
Symmetric_key des_key;
des_setup(getData(passwd), passwd.length(), 0, &des_key);
des_setup(passwd, 8, 0, &des_key);
auto *input = reinterpret_cast<const unsigned char*>(data.constData());
uchar output[16];
auto *input = getData(data);
des_ecb_encrypt(input, output, &des_key);
des_ecb_encrypt(input + 8, output+8, &des_key);
......@@ -592,14 +587,16 @@ void QVncClient::readClient()
m_state = ClientState::Init;
} else {
// Authentication negotiation
const char supportedSecurity[] {
QByteArray supportedSecurity;
#ifdef QT_VNC_AUTH
SecurityVncAuthentication,
if (!m_password.isEmpty())
supportedSecurity.append(char(SecurityVncAuthentication));
#endif
SecurityNone};
const char size = sizeof(supportedSecurity);
supportedSecurity.append(char(SecurityNone));
const char size = supportedSecurity.size();
m_clientSocket->write(&size, 1);
m_clientSocket->write(supportedSecurity, sizeof(supportedSecurity));
m_clientSocket->write(supportedSecurity);
m_state = ClientState::Security;
// Version 3.8+: This is where we can send a failure message and terminate the
......@@ -613,7 +610,7 @@ void QVncClient::readClient()
if (m_securityType == SecurityVncAuthentication && m_clientSocket->bytesAvailable() >= 16) {
char response[16];
m_clientSocket->read(response, 16);
auto expected = desHash(m_randomChallenge, m_passwordTest);
auto expected = desHash(m_randomChallenge, m_password);
bool passwordMatch = (expected == QByteArray(response, 16));
qDebug() << "Password test" << passwordMatch;
......
......@@ -143,6 +143,8 @@ public slots:
void setDirty(const QRegion &region);
void setPassword(QByteArray password);
private slots:
void readClient();
void discardClient();
......@@ -234,7 +236,7 @@ private:
z_stream_s *m_zlibStream = nullptr;
QImage m_currentImage;
bool m_currentImageIsFlipped = false;
QByteArray m_passwordTest;
QByteArray m_password;
QByteArray m_randomChallenge;
// ### Not nice
......
......@@ -57,6 +57,7 @@ public:
bool isFlipped = false;
QVncClientCursor *clientCursor = nullptr;
mutable QReadWriteLock screenImageLock;
QByteArray password;
};
QVncServer::QVncServer(const QSize &screenSize, QImage::Format screenFormat, quint16 port)
......@@ -86,6 +87,7 @@ void QVncServer::incomingConnection(qintptr handle)
Q_D(QVncServer);
QVncClient *client = new QVncClient(this);
client->setPassword(d->password);
client->initialize(handle);
d->clients.append(client);
......@@ -191,7 +193,6 @@ void QVncServer::setIsConnected(bool newIsConnected)
emit isConnectedChanged(newIsConnected);
}
void QVncServer::provideImage(const QImage &image, bool flippedVertically)
{
Q_D(QVncServer);
......@@ -223,4 +224,22 @@ QVncClientCursor *QVncServer::clientCursor() const
return d->clientCursor;
}
const QByteArray &QVncServer::password() const
{
Q_D(const QVncServer);
return d->password;
}
void QVncServer::setPassword(const QByteArray &newPassword)
{
Q_D(QVncServer);
if (d->password == newPassword)
return;
d->password = newPassword;
for (auto client : qAsConst(d->clients))
QMetaObject::invokeMethod(client, [newPassword, client]{ client->setPassword(newPassword);});
emit passwordChanged();
}
QT_END_NAMESPACE
......@@ -46,6 +46,7 @@ class Q_VNCSERVER_EXPORT QVncServer : public QTcpServer
{
Q_OBJECT
Q_PROPERTY(bool isConnected READ isConnected NOTIFY isConnectedChanged)
Q_PROPERTY(QByteArray password READ password WRITE setPassword NOTIFY passwordChanged)
Q_DECLARE_PRIVATE(QVncServer)
public:
static constexpr quint16 DefaultPort{5900};
......@@ -64,6 +65,9 @@ public:
bool isConnected() const;
void setCursor(QCursor *cursor);
const QByteArray &password() const;
void setPassword(const QByteArray &newPassword);
Q_SIGNALS:
void mouseEventReceived(QEvent::Type eventType,
const QPointF &mousePosition,
......@@ -79,6 +83,8 @@ Q_SIGNALS:
void requestImage();
void passwordChanged();
protected:
void incomingConnection(qintptr handle) override;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment