PageRenderTime 208ms CodeModel.GetById 52ms app.highlight 74ms RepoModel.GetById 57ms app.codeStats 1ms

/apps/desktop/libvncserver/auth.c

http://ftk.googlecode.com/
C | 375 lines | 215 code | 64 blank | 96 comment | 44 complexity | feddd093061af51c14cc0df88ae5f67f MD5 | raw file
  1/*
  2 * auth.c - deal with authentication.
  3 *
  4 * This file implements the VNC authentication protocol when setting up an RFB
  5 * connection.
  6 */
  7
  8/*
  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.
 13 *
 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.
 18 *
 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.
 23 *
 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,
 27 *  USA.
 28 */
 29
 30#include <rfb/rfb.h>
 31
 32/* RFB 3.8 clients are well informed */
 33void rfbClientSendString(rfbClientPtr cl, char *reason);
 34
 35
 36/*
 37 * Handle security types
 38 */
 39
 40static rfbSecurityHandler* securityHandlers = NULL;
 41
 42/*
 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.
 47 */
 48void
 49rfbRegisterSecurityHandler(rfbSecurityHandler* handler)
 50{
 51	rfbSecurityHandler *head = securityHandlers, *next = NULL;
 52
 53	if(handler == NULL)
 54		return;
 55
 56	next = handler->next;
 57
 58	while(head != NULL) {
 59		if(head == handler) {
 60			rfbRegisterSecurityHandler(next);
 61			return;
 62		}
 63
 64		head = head->next;
 65	}
 66
 67	handler->next = securityHandlers;
 68	securityHandlers = handler;
 69
 70	rfbRegisterSecurityHandler(next);
 71}
 72
 73/*
 74 * This method unregisters a list of security types. 
 75 * These security types won't be available for any new
 76 * client connection. 
 77 */
 78void
 79rfbUnregisterSecurityHandler(rfbSecurityHandler* handler)
 80{
 81	rfbSecurityHandler *cur = NULL, *pre = NULL;
 82
 83	if(handler == NULL)
 84		return;
 85
 86	if(securityHandlers == handler) {
 87		securityHandlers = securityHandlers->next;
 88		rfbUnregisterSecurityHandler(handler->next);
 89		return;
 90	}
 91
 92	cur = pre = securityHandlers;
 93
 94	while(cur) {
 95		if(cur == handler) {
 96			pre->next = cur->next;
 97			break;
 98		}
 99		pre = cur;
100		cur = cur->next;
101	}
102	rfbUnregisterSecurityHandler(handler->next);
103}
104
105/*
106 * Send the authentication challenge.
107 */
108
109static void
110rfbVncAuthSendChallenge(rfbClientPtr cl)
111{
112	
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");
118        rfbCloseClient(cl);
119        return;
120    }
121    
122    /* Dispatch client input to rfbVncAuthProcessResponse. */
123    cl->state = RFB_AUTHENTICATION;
124}
125
126/*
127 * Send the NO AUTHENTICATION. SCARR
128 */
129
130static void
131rfbVncAuthNone(rfbClientPtr cl)
132{
133    uint32_t authResult;
134
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");
140            rfbCloseClient(cl);
141            return;
142        }
143    }
144    cl->state = RFB_INITIALISATION;
145    return;
146}
147
148
149/*
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.
156 */
157
158static rfbSecurityHandler VncSecurityHandlerVncAuth = {
159    rfbSecTypeVncAuth,
160    rfbVncAuthSendChallenge,
161    NULL
162};
163
164static rfbSecurityHandler VncSecurityHandlerNone = {
165    rfbSecTypeNone,
166    rfbVncAuthNone,
167    NULL
168};
169                        
170
171static void
172rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType)
173{
174    /* The size of the message is the count of security types +1,
175     * since the first byte is the number of types. */
176    int size = 1;
177    rfbSecurityHandler* handler;
178#define MAX_SECURITY_TYPES 255
179    uint8_t buffer[MAX_SECURITY_TYPES+1];
180
181
182    /* Fill in the list of security types in the client structure. (NOTE: Not really in the client structure) */
183    switch (primaryType) {
184    case rfbSecTypeNone:
185        rfbRegisterSecurityHandler(&VncSecurityHandlerNone);
186        break;
187    case rfbSecTypeVncAuth:
188        rfbRegisterSecurityHandler(&VncSecurityHandlerVncAuth);
189        break;
190    }
191
192    for (handler = securityHandlers;
193	    handler && size<MAX_SECURITY_TYPES; handler = handler->next) {
194	buffer[size] = handler->type;
195	size++;
196    }
197    buffer[0] = (unsigned char)size-1;
198
199    /* Send the list. */
200    if (rfbWriteExact(cl, (char *)buffer, size) < 0) {
201	rfbLogPerror("rfbSendSecurityTypeList: write");
202	rfbCloseClient(cl);
203	return;
204    }
205
206    /*
207      * if count is 0, we need to send the reason and close the connection.
208      */
209    if(size <= 1) {
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!";
213
214	rfbClientSendString(cl, reason);
215	return;
216    }
217
218    /* Dispatch client input to rfbProcessClientSecurityType. */
219    cl->state = RFB_SECURITY_TYPE;
220}
221
222
223
224
225/*
226 * Tell the client what security type will be used (protocol 3.3).
227 */
228static void
229rfbSendSecurityType(rfbClientPtr cl, int32_t securityType)
230{
231    uint32_t value32;
232
233    /* Send the value. */
234    value32 = Swap32IfLE(securityType);
235    if (rfbWriteExact(cl, (char *)&value32, 4) < 0) {
236	rfbLogPerror("rfbSendSecurityType: write");
237	rfbCloseClient(cl);
238	return;
239    }
240
241    /* Decide what to do next. */
242    switch (securityType) {
243    case rfbSecTypeNone:
244	/* Dispatch client input to rfbProcessClientInitMessage. */
245	cl->state = RFB_INITIALISATION;
246	break;
247    case rfbSecTypeVncAuth:
248	/* Begin the standard VNC authentication procedure. */
249	rfbVncAuthSendChallenge(cl);
250	break;
251    default:
252	/* Impossible case (hopefully). */
253	rfbLogPerror("rfbSendSecurityType: assertion failed");
254	rfbCloseClient(cl);
255    }
256}
257
258
259
260/*
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).
265 */
266
267void
268rfbAuthNewClient(rfbClientPtr cl)
269{
270    int32_t securityType = rfbSecTypeInvalid;
271
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;
277    }
278
279    if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion < 7)
280    {
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");
286	    return;
287	}
288	rfbSendSecurityType(cl, securityType);
289    } else {
290	/* Here it's ok when securityType is set to rfbSecTypeInvalid. */
291	rfbSendSecurityTypeList(cl, securityType);
292    }
293}
294
295/*
296 * Read the security type chosen by the client (protocol 3.7).
297 */
298
299void
300rfbProcessClientSecurityType(rfbClientPtr cl)
301{
302    int n;
303    uint8_t chosenType;
304    rfbSecurityHandler* handler;
305    
306    /* Read the security type. */
307    n = rfbReadExact(cl, (char *)&chosenType, 1);
308    if (n <= 0) {
309	if (n == 0)
310	    rfbLog("rfbProcessClientSecurityType: client gone\n");
311	else
312	    rfbLogPerror("rfbProcessClientSecurityType: read");
313	rfbCloseClient(cl);
314	return;
315    }
316
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);
322	      return;
323	}
324    }
325
326    rfbLog("rfbProcessClientSecurityType: wrong security type (%d) requested\n", chosenType);
327    rfbCloseClient(cl);
328}
329
330
331
332/*
333 * rfbAuthProcessClientMessage is called when the client sends its
334 * authentication response.
335 */
336
337void
338rfbAuthProcessClientMessage(rfbClientPtr cl)
339{
340    int n;
341    uint8_t response[CHALLENGESIZE];
342    uint32_t authResult;
343
344    if ((n = rfbReadExact(cl, (char *)response, CHALLENGESIZE)) <= 0) {
345        if (n != 0)
346            rfbLogPerror("rfbAuthProcessClientMessage: read");
347        rfbCloseClient(cl);
348        return;
349    }
350
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");
356        }
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!");
360	}
361	else
362            rfbCloseClient(cl);
363        return;
364    }
365
366    authResult = Swap32IfLE(rfbVncAuthOK);
367
368    if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) {
369        rfbLogPerror("rfbAuthProcessClientMessage: write");
370        rfbCloseClient(cl);
371        return;
372    }
373
374    cl->state = RFB_INITIALISATION;
375}