• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
33 void rfbClientSendString(rfbClientPtr cl, const char *reason);
34 
35 
36 /*
37  * Handle security types
38  */
39 
40 static 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  */
48 void
rfbRegisterSecurityHandler(rfbSecurityHandler * handler)49 rfbRegisterSecurityHandler(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  */
78 void
rfbUnregisterSecurityHandler(rfbSecurityHandler * handler)79 rfbUnregisterSecurityHandler(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 
109 static void
rfbVncAuthSendChallenge(rfbClientPtr cl)110 rfbVncAuthSendChallenge(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 
141 static void
rfbVncAuthNone(rfbClientPtr cl)142 rfbVncAuthNone(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 
188 static rfbSecurityHandler VncSecurityHandlerVncAuth = {
189     rfbSecTypeVncAuth,
190     rfbVncAuthSendChallenge,
191     NULL
192 };
193 
194 static rfbSecurityHandler VncSecurityHandlerNone = {
195     rfbSecTypeNone,
196     rfbVncAuthNone,
197     NULL
198 };
199 
200 
201 static void
rfbSendSecurityTypeList(rfbClientPtr cl,int primaryType)202 rfbSendSecurityTypeList(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  */
258 static void
rfbSendSecurityType(rfbClientPtr cl,int32_t securityType)259 rfbSendSecurityType(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 
297 void
rfbAuthNewClient(rfbClientPtr cl)298 rfbAuthNewClient(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 
329 void
rfbProcessClientSecurityType(rfbClientPtr cl)330 rfbProcessClientSecurityType(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 
367 void
rfbAuthProcessClientMessage(rfbClientPtr cl)368 rfbAuthProcessClientMessage(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