LibVNCServer/LibVNCClient
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
auth.c
Go to the documentation of this 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 */
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
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) {
61  return;
62  }
63 
64  head = head->next;
65  }
66 
67  handler->next = securityHandlers;
68  securityHandlers = handler;
69 
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
80 {
81  rfbSecurityHandler *cur = NULL, *pre = NULL;
82 
83  if(handler == NULL)
84  return;
85 
86  if(securityHandlers == handler) {
87  securityHandlers = securityHandlers->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  }
103 }
104 
105 /*
106  * Send the authentication challenge.
107  */
108 
109 static void
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
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). */
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 = {
190  rfbVncAuthSendChallenge,
191  NULL
192 };
193 
194 static rfbSecurityHandler VncSecurityHandlerNone = {
196  rfbVncAuthNone,
197  NULL
198 };
199 
200 
201 static void
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
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
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
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
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 }