--- /dev/null
+/*
+ * 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, 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
+ */
+
+static void
+rfbVncAuthNone(rfbClientPtr cl)
+{
+ uint32_t authResult;
+
+ if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion > 7) {
+ 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 = RFB_INITIALISATION;
+ 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;
+}