/* * 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 . * 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 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 && 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!"; 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; }