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, const 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
130/*
131 * The rfbVncAuthNone function is currently the only function that contains
132 * special logic for the built-in Mac OS X VNC client which is activated by
133 * a protocolMinorVersion == 889 coming from the Mac OS X VNC client.
134 * The rfbProcessClientInitMessage function does understand how to handle the
135 * RFB_INITIALISATION_SHARED state which was introduced to support the built-in
136 * Mac OS X VNC client, but rfbProcessClientInitMessage does not examine the
137 * protocolMinorVersion version field and so its support for the
138 * RFB_INITIALISATION_SHARED state is not restricted to just the OS X client.
139 */
140
141static void
142rfbVncAuthNone(rfbClientPtr cl)
143{
144    /* The built-in Mac OS X VNC client behaves in a non-conforming fashion
145     * when the server version is 3.7 or later AND the list of security types
146     * sent to the OS X client contains the 'None' authentication type AND
147     * the OS X client sends back the 'None' type as its choice.  In this case,
148     * and this case ONLY, the built-in Mac OS X VNC client will NOT send the
149     * ClientInit message and instead will behave as though an implicit
150     * ClientInit message containing a shared-flag of true has been sent.
151     * The special state RFB_INITIALISATION_SHARED represents this case.
152     * The Mac OS X VNC client can be detected by checking protocolMinorVersion
153     * for a value of 889.  No other VNC client is known to use this value
154     * for protocolMinorVersion. */
155    uint32_t authResult;
156
157    /* The built-in Mac OS X VNC client expects to NOT receive a SecurityResult
158     * message for authentication type 'None'.  Since its protocolMinorVersion
159     * is greater than 7 (it is 889) this case must be tested for specially. */
160    if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion > 7 && cl->protocolMinorVersion != 889) {
161        rfbLog("rfbProcessClientSecurityType: returning securityResult for client rfb version >= 3.8\n");
162        authResult = Swap32IfLE(rfbVncAuthOK);
163        if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) {
164            rfbLogPerror("rfbAuthProcessClientMessage: write");
165            rfbCloseClient(cl);
166            return;
167        }
168    }
169    cl->state = cl->protocolMinorVersion == 889 ? RFB_INITIALISATION_SHARED : RFB_INITIALISATION;
170    if (cl->state == RFB_INITIALISATION_SHARED)
171        /* In this case we must call rfbProcessClientMessage now because
172         * otherwise we would hang waiting for data to be received from the
173         * client (the ClientInit message which will never come). */
174        rfbProcessClientMessage(cl);
175    return;
176}
177
178
179/*
180 * Advertise the supported security types (protocol 3.7). Here before sending
181 * the list of security types to the client one more security type is added
182 * to the list if primaryType is not set to rfbSecTypeInvalid. This security
183 * type is the standard vnc security type which does the vnc authentication
184 * or it will be security type for no authentication.
185 * Different security types will be added by applications using this library.
186 */
187
188static rfbSecurityHandler VncSecurityHandlerVncAuth = {
189    rfbSecTypeVncAuth,
190    rfbVncAuthSendChallenge,
191    NULL
192};
193
194static rfbSecurityHandler VncSecurityHandlerNone = {
195    rfbSecTypeNone,
196    rfbVncAuthNone,
197    NULL
198};
199
200
201static void
202rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType)
203{
204    /* The size of the message is the count of security types +1,
205     * since the first byte is the number of types. */
206    int size = 1;
207    rfbSecurityHandler* handler;
208#define MAX_SECURITY_TYPES 255
209    uint8_t buffer[MAX_SECURITY_TYPES+1];
210
211
212    /* Fill in the list of security types in the client structure. (NOTE: Not really in the client structure) */
213    switch (primaryType) {
214    case rfbSecTypeNone:
215        rfbRegisterSecurityHandler(&VncSecurityHandlerNone);
216        break;
217    case rfbSecTypeVncAuth:
218        rfbRegisterSecurityHandler(&VncSecurityHandlerVncAuth);
219        break;
220    }
221
222    for (handler = securityHandlers;
223	    handler && size<MAX_SECURITY_TYPES; handler = handler->next) {
224	buffer[size] = handler->type;
225	size++;
226    }
227    buffer[0] = (unsigned char)size-1;
228
229    /* Send the list. */
230    if (rfbWriteExact(cl, (char *)buffer, size) < 0) {
231	rfbLogPerror("rfbSendSecurityTypeList: write");
232	rfbCloseClient(cl);
233	return;
234    }
235
236    /*
237      * if count is 0, we need to send the reason and close the connection.
238      */
239    if(size <= 1) {
240	/* This means total count is Zero and so reason msg should be sent */
241	/* The execution should never reach here */
242	char* reason = "No authentication mode is registered!";
243
244	rfbClientSendString(cl, reason);
245	return;
246    }
247
248    /* Dispatch client input to rfbProcessClientSecurityType. */
249    cl->state = RFB_SECURITY_TYPE;
250}
251
252
253
254
255/*
256 * Tell the client what security type will be used (protocol 3.3).
257 */
258static void
259rfbSendSecurityType(rfbClientPtr cl, int32_t securityType)
260{
261    uint32_t value32;
262
263    /* Send the value. */
264    value32 = Swap32IfLE(securityType);
265    if (rfbWriteExact(cl, (char *)&value32, 4) < 0) {
266	rfbLogPerror("rfbSendSecurityType: write");
267	rfbCloseClient(cl);
268	return;
269    }
270
271    /* Decide what to do next. */
272    switch (securityType) {
273    case rfbSecTypeNone:
274	/* Dispatch client input to rfbProcessClientInitMessage. */
275	cl->state = RFB_INITIALISATION;
276	break;
277    case rfbSecTypeVncAuth:
278	/* Begin the standard VNC authentication procedure. */
279	rfbVncAuthSendChallenge(cl);
280	break;
281    default:
282	/* Impossible case (hopefully). */
283	rfbLogPerror("rfbSendSecurityType: assertion failed");
284	rfbCloseClient(cl);
285    }
286}
287
288
289
290/*
291 * rfbAuthNewClient is called right after negotiating the protocol
292 * version. Depending on the protocol version, we send either a code
293 * for authentication scheme to be used (protocol 3.3), or a list of
294 * possible "security types" (protocol 3.7).
295 */
296
297void
298rfbAuthNewClient(rfbClientPtr cl)
299{
300    int32_t securityType = rfbSecTypeInvalid;
301
302    if (!cl->screen->authPasswdData || cl->reverseConnection) {
303	/* chk if this condition is valid or not. */
304	securityType = rfbSecTypeNone;
305    } else if (cl->screen->authPasswdData) {
306 	    securityType = rfbSecTypeVncAuth;
307    }
308
309    if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion < 7)
310    {
311	/* Make sure we use only RFB 3.3 compatible security types. */
312	if (securityType == rfbSecTypeInvalid) {
313	    rfbLog("VNC authentication disabled - RFB 3.3 client rejected\n");
314	    rfbClientConnFailed(cl, "Your viewer cannot handle required "
315				"authentication methods");
316	    return;
317	}
318	rfbSendSecurityType(cl, securityType);
319    } else {
320	/* Here it's ok when securityType is set to rfbSecTypeInvalid. */
321	rfbSendSecurityTypeList(cl, securityType);
322    }
323}
324
325/*
326 * Read the security type chosen by the client (protocol 3.7).
327 */
328
329void
330rfbProcessClientSecurityType(rfbClientPtr cl)
331{
332    int n;
333    uint8_t chosenType;
334    rfbSecurityHandler* handler;
335
336    /* Read the security type. */
337    n = rfbReadExact(cl, (char *)&chosenType, 1);
338    if (n <= 0) {
339	if (n == 0)
340	    rfbLog("rfbProcessClientSecurityType: client gone\n");
341	else
342	    rfbLogPerror("rfbProcessClientSecurityType: read");
343	rfbCloseClient(cl);
344	return;
345    }
346
347    /* Make sure it was present in the list sent by the server. */
348    for (handler = securityHandlers; handler; handler = handler->next) {
349	if (chosenType == handler->type) {
350	      rfbLog("rfbProcessClientSecurityType: executing handler for type %d\n", chosenType);
351	      handler->handler(cl);
352	      return;
353	}
354    }
355
356    rfbLog("rfbProcessClientSecurityType: wrong security type (%d) requested\n", chosenType);
357    rfbCloseClient(cl);
358}
359
360
361
362/*
363 * rfbAuthProcessClientMessage is called when the client sends its
364 * authentication response.
365 */
366
367void
368rfbAuthProcessClientMessage(rfbClientPtr cl)
369{
370    int n;
371    uint8_t response[CHALLENGESIZE];
372    uint32_t authResult;
373
374    if ((n = rfbReadExact(cl, (char *)response, CHALLENGESIZE)) <= 0) {
375        if (n != 0)
376            rfbLogPerror("rfbAuthProcessClientMessage: read");
377        rfbCloseClient(cl);
378        return;
379    }
380
381    if(!cl->screen->passwordCheck(cl,(const char*)response,CHALLENGESIZE)) {
382        rfbErr("rfbAuthProcessClientMessage: password check failed\n");
383        authResult = Swap32IfLE(rfbVncAuthFailed);
384        if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) {
385            rfbLogPerror("rfbAuthProcessClientMessage: write");
386        }
387	/* support RFB 3.8 clients, they expect a reason *why* it was disconnected */
388        if (cl->protocolMinorVersion > 7) {
389            rfbClientSendString(cl, "password check failed!");
390	}
391	else
392            rfbCloseClient(cl);
393        return;
394    }
395
396    authResult = Swap32IfLE(rfbVncAuthOK);
397
398    if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) {
399        rfbLogPerror("rfbAuthProcessClientMessage: write");
400        rfbCloseClient(cl);
401        return;
402    }
403
404    cl->state = RFB_INITIALISATION;
405}
406