| /* |
| * auth.c - deal with authentication. |
| * |
| * This file implements the VNC authentication protocol when setting up an RFB |
| * connection. |
| */ |
| |
| /* |
| * Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin |
| * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>. |
| * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge. |
| * All Rights Reserved. |
| * |
| * This is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This software is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this software; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| * USA. |
| */ |
| |
| #include <rfb/rfb.h> |
| |
| /* RFB 3.8 clients are well informed */ |
| void rfbClientSendString(rfbClientPtr cl, const char *reason); |
| |
| |
| /* |
| * Handle security types |
| */ |
| |
| 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) |
| { |
| rfbSecurityHandler *head = securityHandlers, *next = NULL; |
| |
| if(handler == NULL) |
| return; |
| |
| next = handler->next; |
| |
| while(head != NULL) { |
| if(head == handler) { |
| rfbRegisterSecurityHandler(next); |
| return; |
| } |
| |
| head = head->next; |
| } |
| |
| handler->next = securityHandlers; |
| securityHandlers = handler; |
| |
| rfbRegisterSecurityHandler(next); |
| } |
| |
| /* |
| * This method unregisters a list of security types. |
| * These security types won't be available for any new |
| * client connection. |
| */ |
| void |
| rfbUnregisterSecurityHandler(rfbSecurityHandler* handler) |
| { |
| rfbSecurityHandler *cur = NULL, *pre = NULL; |
| |
| if(handler == NULL) |
| return; |
| |
| if(securityHandlers == handler) { |
| securityHandlers = securityHandlers->next; |
| rfbUnregisterSecurityHandler(handler->next); |
| return; |
| } |
| |
| cur = pre = securityHandlers; |
| |
| while(cur) { |
| if(cur == handler) { |
| pre->next = cur->next; |
| break; |
| } |
| pre = cur; |
| cur = cur->next; |
| } |
| rfbUnregisterSecurityHandler(handler->next); |
| } |
| |
| /* |
| * Send the authentication challenge. |
| */ |
| |
| 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; |
| } |
| |
| /* |
| * Send the NO AUTHENTICATION. SCARR |
| */ |
| |
| /* |
| * The rfbVncAuthNone function is currently the only function that contains |
| * special logic for the built-in Mac OS X VNC client which is activated by |
| * a protocolMinorVersion == 889 coming from the Mac OS X VNC client. |
| * The rfbProcessClientInitMessage function does understand how to handle the |
| * RFB_INITIALISATION_SHARED state which was introduced to support the built-in |
| * Mac OS X VNC client, but rfbProcessClientInitMessage does not examine the |
| * protocolMinorVersion version field and so its support for the |
| * RFB_INITIALISATION_SHARED state is not restricted to just the OS X client. |
| */ |
| |
| static void |
| rfbVncAuthNone(rfbClientPtr cl) |
| { |
| /* The built-in Mac OS X VNC client behaves in a non-conforming fashion |
| * when the server version is 3.7 or later AND the list of security types |
| * sent to the OS X client contains the 'None' authentication type AND |
| * the OS X client sends back the 'None' type as its choice. In this case, |
| * and this case ONLY, the built-in Mac OS X VNC client will NOT send the |
| * ClientInit message and instead will behave as though an implicit |
| * ClientInit message containing a shared-flag of true has been sent. |
| * The special state RFB_INITIALISATION_SHARED represents this case. |
| * The Mac OS X VNC client can be detected by checking protocolMinorVersion |
| * for a value of 889. No other VNC client is known to use this value |
| * for protocolMinorVersion. */ |
| uint32_t authResult; |
| |
| /* The built-in Mac OS X VNC client expects to NOT receive a SecurityResult |
| * message for authentication type 'None'. Since its protocolMinorVersion |
| * is greater than 7 (it is 889) this case must be tested for specially. */ |
| if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion > 7 && cl->protocolMinorVersion != 889) { |
| rfbLog("rfbProcessClientSecurityType: returning securityResult for client rfb version >= 3.8\n"); |
| authResult = Swap32IfLE(rfbVncAuthOK); |
| if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) { |
| rfbLogPerror("rfbAuthProcessClientMessage: write"); |
| rfbCloseClient(cl); |
| return; |
| } |
| } |
| cl->state = cl->protocolMinorVersion == 889 ? RFB_INITIALISATION_SHARED : RFB_INITIALISATION; |
| if (cl->state == RFB_INITIALISATION_SHARED) |
| /* In this case we must call rfbProcessClientMessage now because |
| * otherwise we would hang waiting for data to be received from the |
| * client (the ClientInit message which will never come). */ |
| rfbProcessClientMessage(cl); |
| return; |
| } |
| |
| |
| /* |
| * 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 rfbSecurityHandler VncSecurityHandlerVncAuth = { |
| rfbSecTypeVncAuth, |
| rfbVncAuthSendChallenge, |
| NULL |
| }; |
| |
| static rfbSecurityHandler VncSecurityHandlerNone = { |
| rfbSecTypeNone, |
| rfbVncAuthNone, |
| NULL |
| }; |
| |
| |
| 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. (NOTE: Not really in the client structure) */ |
| switch (primaryType) { |
| case rfbSecTypeNone: |
| rfbRegisterSecurityHandler(&VncSecurityHandlerNone); |
| break; |
| case rfbSecTypeVncAuth: |
| rfbRegisterSecurityHandler(&VncSecurityHandlerVncAuth); |
| break; |
| } |
| |
| for (handler = securityHandlers; |
| handler && size<MAX_SECURITY_TYPES; handler = handler->next) { |
| 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!"; |
| |
| rfbClientSendString(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->protocolMajorVersion==3 && 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; |
| 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; |
| } |
| |
| /* Make sure it was present in the list sent by the server. */ |
| for (handler = securityHandlers; handler; handler = handler->next) { |
| if (chosenType == handler->type) { |
| rfbLog("rfbProcessClientSecurityType: executing handler for type %d\n", chosenType); |
| handler->handler(cl); |
| return; |
| } |
| } |
| |
| rfbLog("rfbProcessClientSecurityType: wrong security type (%d) requested\n", chosenType); |
| rfbCloseClient(cl); |
| } |
| |
| |
| |
| /* |
| * rfbAuthProcessClientMessage is called when the client sends its |
| * authentication response. |
| */ |
| |
| void |
| rfbAuthProcessClientMessage(rfbClientPtr cl) |
| { |
| int n; |
| uint8_t response[CHALLENGESIZE]; |
| uint32_t authResult; |
| |
| if ((n = rfbReadExact(cl, (char *)response, CHALLENGESIZE)) <= 0) { |
| if (n != 0) |
| rfbLogPerror("rfbAuthProcessClientMessage: read"); |
| rfbCloseClient(cl); |
| return; |
| } |
| |
| if(!cl->screen->passwordCheck(cl,(const char*)response,CHALLENGESIZE)) { |
| rfbErr("rfbAuthProcessClientMessage: password check failed\n"); |
| authResult = Swap32IfLE(rfbVncAuthFailed); |
| if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) { |
| rfbLogPerror("rfbAuthProcessClientMessage: write"); |
| } |
| /* support RFB 3.8 clients, they expect a reason *why* it was disconnected */ |
| if (cl->protocolMinorVersion > 7) { |
| rfbClientSendString(cl, "password check failed!"); |
| } |
| else |
| rfbCloseClient(cl); |
| return; |
| } |
| |
| authResult = Swap32IfLE(rfbVncAuthOK); |
| |
| if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) { |
| rfbLogPerror("rfbAuthProcessClientMessage: write"); |
| rfbCloseClient(cl); |
| return; |
| } |
| |
| cl->state = RFB_INITIALISATION; |
| } |