2 * auth.c - deal with authentication.
4 * This file implements the VNC authentication protocol when setting up an RFB
9 * Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
10 * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
11 * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
12 * All Rights Reserved.
14 * This is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This software is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this software; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
32 /* RFB 3.8 clients are well informed */
33 void rfbClientSendString(rfbClientPtr cl, char *reason);
37 * Handle security types
40 static rfbSecurityHandler* securityHandlers = NULL;
43 * This method registers a list of new security types.
44 * It avoids same security type getting registered multiple times.
45 * The order is not preserved if multiple security types are
46 * registered at one-go.
49 rfbRegisterSecurityHandler(rfbSecurityHandler* handler)
51 rfbSecurityHandler *head = securityHandlers, *next = NULL;
60 rfbRegisterSecurityHandler(next);
67 handler->next = securityHandlers;
68 securityHandlers = handler;
70 rfbRegisterSecurityHandler(next);
74 * This method unregisters a list of security types.
75 * These security types won't be available for any new
79 rfbUnregisterSecurityHandler(rfbSecurityHandler* handler)
81 rfbSecurityHandler *cur = NULL, *pre = NULL;
86 if(securityHandlers == handler) {
87 securityHandlers = securityHandlers->next;
88 rfbUnregisterSecurityHandler(handler->next);
92 cur = pre = securityHandlers;
96 pre->next = cur->next;
102 rfbUnregisterSecurityHandler(handler->next);
106 * Send the authentication challenge.
110 rfbVncAuthSendChallenge(rfbClientPtr cl)
113 /* 4 byte header is alreay sent. Which is rfbSecTypeVncAuth
114 (same as rfbVncAuth). Just send the challenge. */
115 rfbRandomBytes(cl->authChallenge);
116 if (rfbWriteExact(cl, (char *)cl->authChallenge, CHALLENGESIZE) < 0) {
117 rfbLogPerror("rfbAuthNewClient: write");
122 /* Dispatch client input to rfbVncAuthProcessResponse. */
123 cl->state = RFB_AUTHENTICATION;
127 * Send the NO AUTHENTICATION. SCARR
131 rfbVncAuthNone(rfbClientPtr cl)
135 if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion > 7) {
136 rfbLog("rfbProcessClientSecurityType: returning securityResult for client rfb version >= 3.8\n");
137 authResult = Swap32IfLE(rfbVncAuthOK);
138 if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) {
139 rfbLogPerror("rfbAuthProcessClientMessage: write");
144 cl->state = RFB_INITIALISATION;
150 * Advertise the supported security types (protocol 3.7). Here before sending
151 * the list of security types to the client one more security type is added
152 * to the list if primaryType is not set to rfbSecTypeInvalid. This security
153 * type is the standard vnc security type which does the vnc authentication
154 * or it will be security type for no authentication.
155 * Different security types will be added by applications using this library.
158 static rfbSecurityHandler VncSecurityHandlerVncAuth = {
160 rfbVncAuthSendChallenge,
164 static rfbSecurityHandler VncSecurityHandlerNone = {
172 rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType)
174 /* The size of the message is the count of security types +1,
175 * since the first byte is the number of types. */
177 rfbSecurityHandler* handler;
178 #define MAX_SECURITY_TYPES 255
179 uint8_t buffer[MAX_SECURITY_TYPES+1];
182 /* Fill in the list of security types in the client structure. (NOTE: Not really in the client structure) */
183 switch (primaryType) {
185 rfbRegisterSecurityHandler(&VncSecurityHandlerNone);
187 case rfbSecTypeVncAuth:
188 rfbRegisterSecurityHandler(&VncSecurityHandlerVncAuth);
192 for (handler = securityHandlers;
193 handler && size<MAX_SECURITY_TYPES; handler = handler->next) {
194 buffer[size] = handler->type;
197 buffer[0] = (unsigned char)size-1;
200 if (rfbWriteExact(cl, (char *)buffer, size) < 0) {
201 rfbLogPerror("rfbSendSecurityTypeList: write");
207 * if count is 0, we need to send the reason and close the connection.
210 /* This means total count is Zero and so reason msg should be sent */
211 /* The execution should never reach here */
212 char* reason = "No authentication mode is registered!";
214 rfbClientSendString(cl, reason);
218 /* Dispatch client input to rfbProcessClientSecurityType. */
219 cl->state = RFB_SECURITY_TYPE;
226 * Tell the client what security type will be used (protocol 3.3).
229 rfbSendSecurityType(rfbClientPtr cl, int32_t securityType)
233 /* Send the value. */
234 value32 = Swap32IfLE(securityType);
235 if (rfbWriteExact(cl, (char *)&value32, 4) < 0) {
236 rfbLogPerror("rfbSendSecurityType: write");
241 /* Decide what to do next. */
242 switch (securityType) {
244 /* Dispatch client input to rfbProcessClientInitMessage. */
245 cl->state = RFB_INITIALISATION;
247 case rfbSecTypeVncAuth:
248 /* Begin the standard VNC authentication procedure. */
249 rfbVncAuthSendChallenge(cl);
252 /* Impossible case (hopefully). */
253 rfbLogPerror("rfbSendSecurityType: assertion failed");
261 * rfbAuthNewClient is called right after negotiating the protocol
262 * version. Depending on the protocol version, we send either a code
263 * for authentication scheme to be used (protocol 3.3), or a list of
264 * possible "security types" (protocol 3.7).
268 rfbAuthNewClient(rfbClientPtr cl)
270 int32_t securityType = rfbSecTypeInvalid;
272 if (!cl->screen->authPasswdData || cl->reverseConnection) {
273 /* chk if this condition is valid or not. */
274 securityType = rfbSecTypeNone;
275 } else if (cl->screen->authPasswdData) {
276 securityType = rfbSecTypeVncAuth;
279 if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion < 7)
281 /* Make sure we use only RFB 3.3 compatible security types. */
282 if (securityType == rfbSecTypeInvalid) {
283 rfbLog("VNC authentication disabled - RFB 3.3 client rejected\n");
284 rfbClientConnFailed(cl, "Your viewer cannot handle required "
285 "authentication methods");
288 rfbSendSecurityType(cl, securityType);
290 /* Here it's ok when securityType is set to rfbSecTypeInvalid. */
291 rfbSendSecurityTypeList(cl, securityType);
296 * Read the security type chosen by the client (protocol 3.7).
300 rfbProcessClientSecurityType(rfbClientPtr cl)
304 rfbSecurityHandler* handler;
306 /* Read the security type. */
307 n = rfbReadExact(cl, (char *)&chosenType, 1);
310 rfbLog("rfbProcessClientSecurityType: client gone\n");
312 rfbLogPerror("rfbProcessClientSecurityType: read");
317 /* Make sure it was present in the list sent by the server. */
318 for (handler = securityHandlers; handler; handler = handler->next) {
319 if (chosenType == handler->type) {
320 rfbLog("rfbProcessClientSecurityType: executing handler for type %d\n", chosenType);
321 handler->handler(cl);
326 rfbLog("rfbProcessClientSecurityType: wrong security type (%d) requested\n", chosenType);
333 * rfbAuthProcessClientMessage is called when the client sends its
334 * authentication response.
338 rfbAuthProcessClientMessage(rfbClientPtr cl)
341 uint8_t response[CHALLENGESIZE];
344 if ((n = rfbReadExact(cl, (char *)response, CHALLENGESIZE)) <= 0) {
346 rfbLogPerror("rfbAuthProcessClientMessage: read");
351 if(!cl->screen->passwordCheck(cl,(const char*)response,CHALLENGESIZE)) {
352 rfbErr("rfbAuthProcessClientMessage: password check failed\n");
353 authResult = Swap32IfLE(rfbVncAuthFailed);
354 if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) {
355 rfbLogPerror("rfbAuthProcessClientMessage: write");
357 /* support RFB 3.8 clients, they expect a reason *why* it was disconnected */
358 if (cl->protocolMinorVersion > 7) {
359 rfbClientSendString(cl, "password check failed!");
366 authResult = Swap32IfLE(rfbVncAuthOK);
368 if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) {
369 rfbLogPerror("rfbAuthProcessClientMessage: write");
374 cl->state = RFB_INITIALISATION;