From da7b3e714f8f9b501cb13075f6433416410bd6aa Mon Sep 17 00:00:00 2001 From: dscho Date: Mon, 26 Sep 2005 13:17:33 +0000 Subject: support VNC protocol version 3.7 --- ChangeLog | 5 ++ libvncserver/auth.c | 215 +++++++++++++++++++++++++++++++++++++++++++---- libvncserver/main.c | 1 + libvncserver/rfbserver.c | 17 +++- rfb/rfb.h | 22 ++++- rfb/rfbproto.h | 21 ++++- 6 files changed, 258 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index 96eb979..42e21a6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2005-09-26 Rohit Kumar + * libvncserver/{auth,main,rfbserver}.c, rfb/{rfb,rfbproto}.h: + support VNC protocol version 3.7. This allows to add security + types. + 2005-08-21 Alberto Lusiani * libvncserver.spec.in: split rpm into libvncserver, -devel and x11vnc diff --git a/libvncserver/auth.c b/libvncserver/auth.c index 0988538..98dc48e 100755 --- a/libvncserver/auth.c +++ b/libvncserver/auth.c @@ -6,6 +6,7 @@ */ /* + * Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin * OSXvnc Copyright (C) 2001 Dan McGuirk . * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge. * All Rights Reserved. @@ -29,38 +30,216 @@ #include /* - * rfbAuthNewClient is called when we reach the point of authenticating - * a new client. If authentication isn't being used then we simply send - * rfbNoAuth. Otherwise we send rfbVncAuth plus the challenge. + * Handle security types */ void -rfbAuthNewClient(rfbClientPtr cl) +rfbRegisterSecurityHandler(rfbScreenInfoPtr server, rfbSecurityHandler* handler) { - char buf[4 + CHALLENGESIZE]; - int len; + rfbSecurityHandler* last = handler; - cl->state = RFB_AUTHENTICATION; + while(last->next) + last = last->next; - if (cl->screen->authPasswdData && !cl->reverseConnection) { - *(uint32_t *)buf = Swap32IfLE(rfbVncAuth); - rfbRandomBytes(cl->authChallenge); - memcpy(&buf[4], (char *)cl->authChallenge, CHALLENGESIZE); - len = 4 + CHALLENGESIZE; - } else { - *(uint32_t *)buf = Swap32IfLE(rfbNoAuth); - len = 4; - cl->state = RFB_INITIALISATION; - } + last->next = server->securityHandlers; + server->securityHandlers = handler; +} + + +/* + * Send the authentication challenge. + */ - if (rfbWriteExact(cl, buf, len) < 0) { +static void +rfbVncAuthSendChallenge(rfbClientPtr cl) +{ + + /* 4 byte header is alreay sent. Which is rfbSecTypeVncAuth + (same as rfbVncAuth). Just send the challenge. */ + rfbRandomBytes(cl->authChallenge); + if (rfbWriteExact(cl, (char *)cl->authChallenge, CHALLENGESIZE) < 0) { rfbLogPerror("rfbAuthNewClient: write"); rfbCloseClient(cl); return; } + + /* Dispatch client input to rfbVncAuthProcessResponse. */ + cl->state = RFB_AUTHENTICATION; } +/* + * Advertise the supported security types (protocol 3.7). Here before sending + * the list of security types to the client one more security type is added + * to the list if primaryType is not set to rfbSecTypeInvalid. This security + * type is the standard vnc security type which does the vnc authentication + * or it will be security type for no authentication. + * Different security types will be added by applications using this library. + */ + +static void +rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType) +{ + /* The size of the message is the count of security types +1, + * since the first byte is the number of types. */ + int size = 1; + rfbSecurityHandler* handler; +#define MAX_SECURITY_TYPES 255 + uint8_t buffer[MAX_SECURITY_TYPES+1]; + + /* Fill in the list of security types in the client structure. */ + if (primaryType != rfbSecTypeInvalid) { + rfbSecurityHandler* handler = calloc(sizeof(rfbSecurityHandler),1); + handler->type = primaryType; + handler->handler = rfbVncAuthSendChallenge; + handler->next = NULL; + rfbRegisterSecurityHandler(cl->screen, handler); + } + + for (handler = cl->screen->securityHandlers; + handler && sizenext) { + buffer[size] = handler->type; + size++; + } + buffer[0] = (unsigned char)size-1; + + /* Send the list. */ + if (rfbWriteExact(cl, (char *)buffer, size) < 0) { + rfbLogPerror("rfbSendSecurityTypeList: write"); + rfbCloseClient(cl); + return; + } + + /* + * if count is 0, we need to send the reason and close the connection. + */ + if(size <= 1) { + /* This means total count is Zero and so reason msg should be sent */ + /* The execution should never reach here */ + char* reason = "No authentication mode is registered!"; + + rfbClientConnFailed(cl, reason); + return; + } + + /* Dispatch client input to rfbProcessClientSecurityType. */ + cl->state = RFB_SECURITY_TYPE; +} + + + + +/* + * Tell the client what security type will be used (protocol 3.3). + */ +static void +rfbSendSecurityType(rfbClientPtr cl, int32_t securityType) +{ + uint32_t value32; + + /* Send the value. */ + value32 = Swap32IfLE(securityType); + if (rfbWriteExact(cl, (char *)&value32, 4) < 0) { + rfbLogPerror("rfbSendSecurityType: write"); + rfbCloseClient(cl); + return; + } + + /* Decide what to do next. */ + switch (securityType) { + case rfbSecTypeNone: + /* Dispatch client input to rfbProcessClientInitMessage. */ + cl->state = RFB_INITIALISATION; + break; + case rfbSecTypeVncAuth: + /* Begin the standard VNC authentication procedure. */ + rfbVncAuthSendChallenge(cl); + break; + default: + /* Impossible case (hopefully). */ + rfbLogPerror("rfbSendSecurityType: assertion failed"); + rfbCloseClient(cl); + } +} + + + +/* + * rfbAuthNewClient is called right after negotiating the protocol + * version. Depending on the protocol version, we send either a code + * for authentication scheme to be used (protocol 3.3), or a list of + * possible "security types" (protocol 3.7). + */ + +void +rfbAuthNewClient(rfbClientPtr cl) +{ + int32_t securityType = rfbSecTypeInvalid; + + if (!cl->screen->authPasswdData || cl->reverseConnection) { + // chk if this condition is valid or not. + securityType = rfbSecTypeNone; + } else if (cl->screen->authPasswdData) { + securityType = rfbSecTypeVncAuth; + } + + if (cl->protocolMinorVersion < 7) { + /* Make sure we use only RFB 3.3 compatible security types. */ + if (securityType == rfbSecTypeInvalid) { + rfbLog("VNC authentication disabled - RFB 3.3 client rejected\n"); + rfbClientConnFailed(cl, "Your viewer cannot handle required " + "authentication methods"); + return; + } + rfbSendSecurityType(cl, securityType); + } else { + /* Here it's ok when securityType is set to rfbSecTypeInvalid. */ + rfbSendSecurityTypeList(cl, securityType); + } +} + +/* + * Read the security type chosen by the client (protocol 3.7). + */ + +void +rfbProcessClientSecurityType(rfbClientPtr cl) +{ + int n, i; + uint8_t chosenType; + rfbSecurityHandler* handler; + + /* Read the security type. */ + n = rfbReadExact(cl, (char *)&chosenType, 1); + if (n <= 0) { + if (n == 0) + rfbLog("rfbProcessClientSecurityType: client gone\n"); + else + rfbLogPerror("rfbProcessClientSecurityType: read"); + rfbCloseClient(cl); + return; + } + + if(chosenType == rfbSecTypeNone) { + cl->state = RFB_INITIALISATION; + return; + } + + + /* Make sure it was present in the list sent by the server. */ + for (handler = cl->screen->securityHandlers; handler; + handler = handler->next) + if (chosenType == handler->type) { + handler->handler(cl); + return; + } + + rfbLog("rfbProcessClientSecurityType: wrong security type requested\n"); + rfbCloseClient(cl); +} + + + /* * rfbAuthProcessClientMessage is called when the client sends its * authentication response. diff --git a/libvncserver/main.c b/libvncserver/main.c index a9161ce..5a3d248 100644 --- a/libvncserver/main.c +++ b/libvncserver/main.c @@ -668,6 +668,7 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv, screen->newClientHook = rfbDefaultNewClientHook; screen->displayHook = NULL; screen->processCustomClientMessage = rfbDefaultProcessCustomClientMessage; + screen->securityHandlers = NULL; /* initialize client list and iterator mutex */ rfbClientListInit(screen); diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c index 745589e..1f71a18 100644 --- a/libvncserver/rfbserver.c +++ b/libvncserver/rfbserver.c @@ -487,6 +487,9 @@ rfbProcessClientMessage(rfbClientPtr cl) case RFB_PROTOCOL_VERSION: rfbProcessClientProtocolVersion(cl); return; + case RFB_SECURITY_TYPE: + rfbProcessClientSecurityType(cl); + return; case RFB_AUTHENTICATION: rfbAuthProcessClientMessage(cl); return; @@ -545,9 +548,17 @@ rfbProcessClientProtocolVersion(rfbClientPtr cl) return; } - if (minor_ != rfbProtocolMinorVersion) { - /* Minor version mismatch - warn but try to continue */ - rfbLog("Ignoring minor version mismatch\n"); + // Chk for the minor version use either of the two standard version of RFB + cl->protocolMinorVersion = minor_; + if (minor_ > rfbProtocolMinorVersion) { + cl->protocolMinorVersion = rfbProtocolMinorVersion; + } else if (minor_ < rfbProtocolMinorVersion) { + cl->protocolMinorVersion = rfbProtocolFallbackMinorVersion; + } + if (minor_ != rfbProtocolMinorVersion && + minor_ != rfbProtocolFallbackMinorVersion) { + rfbLog("Non-standard protocol version %d.%d, using %d.%d instead\n", + major_, minor_, rfbProtocolMajorVersion, cl->protocolMinorVersion); } rfbAuthNewClient(cl); diff --git a/rfb/rfb.h b/rfb/rfb.h index 5866cd6..a63badf 100644 --- a/rfb/rfb.h +++ b/rfb/rfb.h @@ -6,6 +6,8 @@ */ /* + * Copyright (C) 2005 Rohit Kumar , + * Johannes E. Schindelin * Copyright (C) 2002 RealVNC Ltd. * OSXvnc Copyright (C) 2001 Dan McGuirk . * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge. @@ -142,6 +144,17 @@ typedef struct { } data; /* there have to be count*3 entries */ } rfbColourMap; +/* + * Security handling (RFB protocol version 3.7 + */ + +typedef struct _rfbSecurity { + uint8_t type; + void (*handler)(struct _rfbClientRec* cl); + struct _rfbSecurity* next; +} rfbSecurityHandler; + + /* * Per-screen (framebuffer) structure. There can be as many as you wish, * each serving different clients. However, you have to call @@ -265,6 +278,8 @@ typedef struct _rfbScreenInfo rfbProcessCustomClientMessageProcPtr processCustomClientMessage; in_addr_t listenInterface; + + rfbSecurityHandler* securityHandlers; } rfbScreenInfo, *rfbScreenInfoPtr; @@ -307,12 +322,16 @@ typedef struct _rfbClientRec { SOCKET sock; char *host; + /* RFB protocol minor version number */ + int protocolMinorVersion; + #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD pthread_t client_thread; #endif /* Possible client states: */ enum { RFB_PROTOCOL_VERSION, /* establishing protocol version */ + RFB_SECURITY_TYPE, /* negotiating security (RFB v.3.7) */ RFB_AUTHENTICATION, /* authenticating */ RFB_INITIALISATION, /* sending initialisation messages */ RFB_NORMAL /* normal protocol messages */ @@ -582,7 +601,8 @@ extern void rfbHttpCheckFds(rfbScreenInfoPtr rfbScreen); extern void rfbAuthNewClient(rfbClientPtr cl); extern void rfbAuthProcessClientMessage(rfbClientPtr cl); - +extern void rfbRegisterSecurityHandler(rfbScreenInfoPtr server, + rfbSecurityHandler* handler); /* rre.c */ diff --git a/rfb/rfbproto.h b/rfb/rfbproto.h index 179c173..791b5f3 100644 --- a/rfb/rfbproto.h +++ b/rfb/rfbproto.h @@ -2,6 +2,7 @@ #define RFBPROTO_H /* + * Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin * Copyright (C) 2000-2002 Constantin Kaplinsky. All Rights Reserved. * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. @@ -217,12 +218,30 @@ typedef struct { #define rfbProtocolVersionFormat "RFB %03d.%03d\n" #define rfbProtocolMajorVersion 3 -#define rfbProtocolMinorVersion 3 +#define rfbProtocolMinorVersion 7 +#define rfbProtocolFallbackMinorVersion 3 typedef char rfbProtocolVersionMsg[13]; /* allow extra byte for null */ #define sz_rfbProtocolVersionMsg 12 +/* + * Negotiation of the security type (protocol version 3.7) + * + * Once the protocol version has been decided, the server either sends a list + * of supported security types, or informs the client about an error (when the + * number of security types is 0). Security type rfbSecTypeTight is used to + * enable TightVNC-specific protocol extensions. The value rfbSecTypeVncAuth + * stands for classic VNC authentication. + * + * The client selects a particular security type from the list provided by the + * server. + */ + +#define rfbSecTypeInvalid 0 +#define rfbSecTypeNone 1 +#define rfbSecTypeVncAuth 2 + /*----------------------------------------------------------------------------- * Authentication -- cgit v1.2.1