9a9f01d12e
Bundling libvncserver allows backport security updates to libvncserver without having to care about ABI changes, which security updates tend to often result in. RDP is disabled as the freerdp package doesn't provide the server bits, and RDP support isn't fully integrated into GNOME yet. Resolves: #1951301
369 lines
12 KiB
Diff
369 lines
12 KiB
Diff
From c9131a78878a785c3de21e9d49521d7b68400ad7 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
|
|
Date: Mon, 11 Jun 2018 23:50:05 +0200
|
|
Subject: [PATCH 2/4] libvncserver: Add channel security handlers
|
|
|
|
Add another type of security handler that is meant to be used initially
|
|
to set up a secure channel. Regular security handlers would be
|
|
advertised and processed after any channel security have succeeded.
|
|
|
|
For example, this, together with the custom I/O functions allows a
|
|
LibVNCServer user to implement TLS in combination with VNCAuth. This is
|
|
done by adding a single channel security handler with the rfbTLS (18)
|
|
with a handler that initiates a TLS session, and when a TLS session is
|
|
initiated, the regular security handler list is sent.
|
|
---
|
|
libvncserver/auth.c | 164 ++++++++++++++++++++++++++++++---------
|
|
libvncserver/rfbserver.c | 1 +
|
|
rfb/rfb.h | 15 +++-
|
|
3 files changed, 142 insertions(+), 38 deletions(-)
|
|
|
|
diff --git a/libvncserver/auth.c b/libvncserver/auth.c
|
|
index 814a8142..55e0b3c9 100644
|
|
--- a/libvncserver/auth.c
|
|
+++ b/libvncserver/auth.c
|
|
@@ -37,18 +37,17 @@ void rfbClientSendString(rfbClientPtr cl, const char *reason);
|
|
* Handle security types
|
|
*/
|
|
|
|
+/* Channel security handlers to set up a secure channel, e.g. TLS. */
|
|
+static rfbSecurityHandler* channelSecurityHandlers = NULL;
|
|
+
|
|
+/* Security handlers when channel security is established. */
|
|
static rfbSecurityHandler* securityHandlers = NULL;
|
|
|
|
-/*
|
|
- * This method registers a list of new security types.
|
|
- * It avoids same security type getting registered multiple times.
|
|
- * The order is not preserved if multiple security types are
|
|
- * registered at one-go.
|
|
- */
|
|
void
|
|
-rfbRegisterSecurityHandler(rfbSecurityHandler* handler)
|
|
+rfbRegisterSecurityHandlerTo(rfbSecurityHandler* handler,
|
|
+ rfbSecurityHandler** handlerList)
|
|
{
|
|
- rfbSecurityHandler *head = securityHandlers, *next = NULL;
|
|
+ rfbSecurityHandler *head = *handlerList, *next = NULL;
|
|
|
|
if(handler == NULL)
|
|
return;
|
|
@@ -57,39 +56,35 @@ rfbRegisterSecurityHandler(rfbSecurityHandler* handler)
|
|
|
|
while(head != NULL) {
|
|
if(head == handler) {
|
|
- rfbRegisterSecurityHandler(next);
|
|
+ rfbRegisterSecurityHandlerTo(next, handlerList);
|
|
return;
|
|
}
|
|
|
|
head = head->next;
|
|
}
|
|
|
|
- handler->next = securityHandlers;
|
|
- securityHandlers = handler;
|
|
+ handler->next = *handlerList;
|
|
+ *handlerList = handler;
|
|
|
|
- rfbRegisterSecurityHandler(next);
|
|
+ rfbRegisterSecurityHandlerTo(next, handlerList);
|
|
}
|
|
|
|
-/*
|
|
- * This method unregisters a list of security types.
|
|
- * These security types won't be available for any new
|
|
- * client connection.
|
|
- */
|
|
-void
|
|
-rfbUnregisterSecurityHandler(rfbSecurityHandler* handler)
|
|
+static void
|
|
+rfbUnregisterSecurityHandlerFrom(rfbSecurityHandler* handler,
|
|
+ rfbSecurityHandler** handlerList)
|
|
{
|
|
rfbSecurityHandler *cur = NULL, *pre = NULL;
|
|
|
|
if(handler == NULL)
|
|
return;
|
|
|
|
- if(securityHandlers == handler) {
|
|
- securityHandlers = securityHandlers->next;
|
|
- rfbUnregisterSecurityHandler(handler->next);
|
|
+ if(*handlerList == handler) {
|
|
+ *handlerList = (*handlerList)->next;
|
|
+ rfbUnregisterSecurityHandlerFrom(handler->next, handlerList);
|
|
return;
|
|
}
|
|
|
|
- cur = pre = securityHandlers;
|
|
+ cur = pre = *handlerList;
|
|
|
|
while(cur) {
|
|
if(cur == handler) {
|
|
@@ -99,7 +94,50 @@ rfbUnregisterSecurityHandler(rfbSecurityHandler* handler)
|
|
pre = cur;
|
|
cur = cur->next;
|
|
}
|
|
- rfbUnregisterSecurityHandler(handler->next);
|
|
+ rfbUnregisterSecurityHandlerFrom(handler->next, handlerList);
|
|
+}
|
|
+
|
|
+void
|
|
+rfbRegisterChannelSecurityHandler(rfbSecurityHandler* handler)
|
|
+{
|
|
+ rfbRegisterSecurityHandlerTo(handler, &channelSecurityHandlers);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * This method unregisters a list of security types.
|
|
+ * These security types won't be available for any new
|
|
+ * client connection.
|
|
+ */
|
|
+
|
|
+void
|
|
+rfbUnregisterChannelSecurityHandler(rfbSecurityHandler* handler)
|
|
+{
|
|
+ rfbUnregisterSecurityHandlerFrom(handler, &channelSecurityHandlers);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * This method registers a list of new security types.
|
|
+ * It avoids same security type getting registered multiple times.
|
|
+ * The order is not preserved if multiple security types are
|
|
+ * registered at one-go.
|
|
+ */
|
|
+
|
|
+void
|
|
+rfbRegisterSecurityHandler(rfbSecurityHandler* handler)
|
|
+{
|
|
+ rfbRegisterSecurityHandlerTo(handler, &securityHandlers);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * This method unregisters a list of security types.
|
|
+ * These security types won't be available for any new
|
|
+ * client connection.
|
|
+ */
|
|
+
|
|
+void
|
|
+rfbUnregisterSecurityHandler(rfbSecurityHandler* handler)
|
|
+{
|
|
+ rfbUnregisterSecurityHandlerFrom(handler, &securityHandlers);
|
|
}
|
|
|
|
/*
|
|
@@ -197,9 +235,22 @@ static rfbSecurityHandler VncSecurityHandlerNone = {
|
|
NULL
|
|
};
|
|
|
|
+static int32_t
|
|
+determinePrimarySecurityType(rfbClientPtr cl)
|
|
+{
|
|
+ if (!cl->screen->authPasswdData || cl->reverseConnection) {
|
|
+ /* chk if this condition is valid or not. */
|
|
+ return rfbSecTypeNone;
|
|
+ } else if (cl->screen->authPasswdData) {
|
|
+ return rfbSecTypeVncAuth;
|
|
+ } else {
|
|
+ return rfbSecTypeInvalid;
|
|
+ }
|
|
+}
|
|
|
|
-static void
|
|
-rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType)
|
|
+void
|
|
+rfbSendSecurityTypeList(rfbClientPtr cl,
|
|
+ enum rfbSecurityTag exclude)
|
|
{
|
|
/* The size of the message is the count of security types +1,
|
|
* since the first byte is the number of types. */
|
|
@@ -207,9 +258,10 @@ rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType)
|
|
rfbSecurityHandler* handler;
|
|
#define MAX_SECURITY_TYPES 255
|
|
uint8_t buffer[MAX_SECURITY_TYPES+1];
|
|
-
|
|
+ int32_t primaryType;
|
|
|
|
/* Fill in the list of security types in the client structure. (NOTE: Not really in the client structure) */
|
|
+ primaryType = determinePrimarySecurityType(cl);
|
|
switch (primaryType) {
|
|
case rfbSecTypeNone:
|
|
rfbRegisterSecurityHandler(&VncSecurityHandlerNone);
|
|
@@ -221,6 +273,9 @@ rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType)
|
|
|
|
for (handler = securityHandlers;
|
|
handler && size<MAX_SECURITY_TYPES; handler = handler->next) {
|
|
+ if (exclude && (handler->securityTags & exclude))
|
|
+ continue;
|
|
+
|
|
buffer[size] = handler->type;
|
|
size++;
|
|
}
|
|
@@ -249,7 +304,29 @@ rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType)
|
|
cl->state = RFB_SECURITY_TYPE;
|
|
}
|
|
|
|
+static void
|
|
+rfbSendChannelSecurityTypeList(rfbClientPtr cl)
|
|
+{
|
|
+ int size = 1;
|
|
+ rfbSecurityHandler* handler;
|
|
+ uint8_t buffer[MAX_SECURITY_TYPES+1];
|
|
+
|
|
+ for (handler = channelSecurityHandlers;
|
|
+ handler && size<MAX_SECURITY_TYPES; handler = handler->next) {
|
|
+ buffer[size] = handler->type;
|
|
+ size++;
|
|
+ }
|
|
+ buffer[0] = (unsigned char)size-1;
|
|
+
|
|
+ if (rfbWriteExact(cl, (char *)buffer, size) < 0) {
|
|
+ rfbLogPerror("rfbSendSecurityTypeList: write");
|
|
+ rfbCloseClient(cl);
|
|
+ return;
|
|
+ }
|
|
|
|
+ /* Dispatch client input to rfbProcessClientChannelSecurityType. */
|
|
+ cl->state = RFB_CHANNEL_SECURITY_TYPE;
|
|
+}
|
|
|
|
|
|
/*
|
|
@@ -297,18 +374,19 @@ rfbSendSecurityType(rfbClientPtr cl, int32_t securityType)
|
|
void
|
|
rfbAuthNewClient(rfbClientPtr cl)
|
|
{
|
|
- int32_t securityType = rfbSecTypeInvalid;
|
|
+ int32_t securityType;
|
|
|
|
- if (!cl->screen->authPasswdData || cl->reverseConnection) {
|
|
- /* chk if this condition is valid or not. */
|
|
- securityType = rfbSecTypeNone;
|
|
- } else if (cl->screen->authPasswdData) {
|
|
- securityType = rfbSecTypeVncAuth;
|
|
- }
|
|
+ securityType = determinePrimarySecurityType(cl);
|
|
|
|
if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion < 7)
|
|
{
|
|
/* Make sure we use only RFB 3.3 compatible security types. */
|
|
+ if (channelSecurityHandlers) {
|
|
+ rfbLog("VNC channel security enabled - RFB 3.3 client rejected\n");
|
|
+ rfbClientConnFailed(cl, "Your viewer cannot hnadler required "
|
|
+ "security methods");
|
|
+ return;
|
|
+ }
|
|
if (securityType == rfbSecTypeInvalid) {
|
|
rfbLog("VNC authentication disabled - RFB 3.3 client rejected\n");
|
|
rfbClientConnFailed(cl, "Your viewer cannot handle required "
|
|
@@ -316,9 +394,13 @@ rfbAuthNewClient(rfbClientPtr cl)
|
|
return;
|
|
}
|
|
rfbSendSecurityType(cl, securityType);
|
|
+ } else if (channelSecurityHandlers) {
|
|
+ rfbLog("Send channel security type list\n");
|
|
+ rfbSendChannelSecurityTypeList(cl);
|
|
} else {
|
|
/* Here it's ok when securityType is set to rfbSecTypeInvalid. */
|
|
- rfbSendSecurityTypeList(cl, securityType);
|
|
+ rfbLog("Send channel security type 'none'\n");
|
|
+ rfbSendSecurityTypeList(cl, RFB_SECURITY_TAG_NONE);
|
|
}
|
|
}
|
|
|
|
@@ -332,6 +414,7 @@ rfbProcessClientSecurityType(rfbClientPtr cl)
|
|
int n;
|
|
uint8_t chosenType;
|
|
rfbSecurityHandler* handler;
|
|
+ rfbSecurityHandler* handlerListHead;
|
|
|
|
/* Read the security type. */
|
|
n = rfbReadExact(cl, (char *)&chosenType, 1);
|
|
@@ -344,8 +427,17 @@ rfbProcessClientSecurityType(rfbClientPtr cl)
|
|
return;
|
|
}
|
|
|
|
+ switch (cl->state) {
|
|
+ case RFB_CHANNEL_SECURITY_TYPE:
|
|
+ handlerListHead = channelSecurityHandlers;
|
|
+ break;
|
|
+ case RFB_SECURITY_TYPE:
|
|
+ handlerListHead = securityHandlers;
|
|
+ break;
|
|
+ }
|
|
+
|
|
/* Make sure it was present in the list sent by the server. */
|
|
- for (handler = securityHandlers; handler; handler = handler->next) {
|
|
+ for (handler = handlerListHead; handler; handler = handler->next) {
|
|
if (chosenType == handler->type) {
|
|
rfbLog("rfbProcessClientSecurityType: executing handler for type %d\n", chosenType);
|
|
handler->handler(cl);
|
|
diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c
|
|
index 72e9ba79..48eada64 100644
|
|
--- a/libvncserver/rfbserver.c
|
|
+++ b/libvncserver/rfbserver.c
|
|
@@ -652,6 +652,7 @@ rfbProcessClientMessage(rfbClientPtr cl)
|
|
case RFB_PROTOCOL_VERSION:
|
|
rfbProcessClientProtocolVersion(cl);
|
|
return;
|
|
+ case RFB_CHANNEL_SECURITY_TYPE:
|
|
case RFB_SECURITY_TYPE:
|
|
rfbProcessClientSecurityType(cl);
|
|
return;
|
|
diff --git a/rfb/rfb.h b/rfb/rfb.h
|
|
index 3c0b25a3..d136f884 100644
|
|
--- a/rfb/rfb.h
|
|
+++ b/rfb/rfb.h
|
|
@@ -144,6 +144,11 @@ typedef struct {
|
|
} data; /**< there have to be count*3 entries */
|
|
} rfbColourMap;
|
|
|
|
+enum rfbSecurityTag {
|
|
+ RFB_SECURITY_TAG_NONE = 0,
|
|
+ RFB_SECURITY_TAG_CHANNEL = 1 << 0
|
|
+};
|
|
+
|
|
/**
|
|
* Security handling (RFB protocol version 3.7)
|
|
*/
|
|
@@ -152,6 +157,7 @@ typedef struct _rfbSecurity {
|
|
uint8_t type;
|
|
void (*handler)(struct _rfbClientRec* cl);
|
|
struct _rfbSecurity* next;
|
|
+ enum rfbSecurityTag securityTags;
|
|
} rfbSecurityHandler;
|
|
|
|
/**
|
|
@@ -480,7 +486,7 @@ typedef struct _rfbClientRec {
|
|
/** Possible client states: */
|
|
enum {
|
|
RFB_PROTOCOL_VERSION, /**< establishing protocol version */
|
|
- RFB_SECURITY_TYPE, /**< negotiating security (RFB v.3.7) */
|
|
+ RFB_SECURITY_TYPE, /**< negotiating security (RFB v.3.7) */
|
|
RFB_AUTHENTICATION, /**< authenticating */
|
|
RFB_INITIALISATION, /**< sending initialisation messages */
|
|
RFB_NORMAL, /**< normal protocol messages */
|
|
@@ -488,7 +494,9 @@ typedef struct _rfbClientRec {
|
|
/* Ephemeral internal-use states that will never be seen by software
|
|
* using LibVNCServer to provide services: */
|
|
|
|
- RFB_INITIALISATION_SHARED /**< sending initialisation messages with implicit shared-flag already true */
|
|
+ RFB_INITIALISATION_SHARED, /**< sending initialisation messages with implicit shared-flag already true */
|
|
+
|
|
+ RFB_CHANNEL_SECURITY_TYPE, /**< negotiating security (RFB v.3.7) */
|
|
} state;
|
|
|
|
rfbBool reverseConnection;
|
|
@@ -840,6 +848,9 @@ extern void rfbProcessClientSecurityType(rfbClientPtr cl);
|
|
extern void rfbAuthProcessClientMessage(rfbClientPtr cl);
|
|
extern void rfbRegisterSecurityHandler(rfbSecurityHandler* handler);
|
|
extern void rfbUnregisterSecurityHandler(rfbSecurityHandler* handler);
|
|
+extern void rfbRegisterChannelSecurityHandler(rfbSecurityHandler* handler);
|
|
+extern void rfbUnregisterChannelSecurityHandler(rfbSecurityHandler* handler);
|
|
+extern void rfbSendSecurityTypeList(rfbClientPtr cl, enum rfbSecurityTag exclude);
|
|
|
|
/* rre.c */
|
|
|
|
--
|
|
2.28.0
|
|
|