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