From c9131a78878a785c3de21e9d49521d7b68400ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= 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 && sizenext) { + 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 && sizenext) { + 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