You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
369 lines
12 KiB
369 lines
12 KiB
2 years ago
|
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
|
||
|
|