Blame SOURCES/0002-libvncserver-Add-channel-security-handlers.patch

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