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 * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
10 * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
11 * All Rights Reserved.
12 *
13 * This is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This software is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this software; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
26 * USA.
27 */
28
29 #include "rfb/rfb.h"
30
31 void
rfbAuthInitScreen(rfbScreenInfoPtr rfbScreen)32 rfbAuthInitScreen(rfbScreenInfoPtr rfbScreen)
33 {
34 #ifdef VINO_HAVE_GNUTLS
35 #define DH_BITS 1024
36
37 gnutls_global_init();
38
39 gnutls_anon_allocate_server_credentials(&rfbScreen->anonCredentials);
40
41 gnutls_dh_params_init(&rfbScreen->dhParams);
42 gnutls_dh_params_generate2(rfbScreen->dhParams, DH_BITS);
43
44 gnutls_anon_set_server_dh_params(rfbScreen->anonCredentials,
45 rfbScreen->dhParams);
46
47 #undef DH_BITS
48 #endif /* VINO_HAVE_GNUTLS */
49 }
50
51 void
rfbAuthCleanupScreen(rfbScreenInfoPtr rfbScreen)52 rfbAuthCleanupScreen(rfbScreenInfoPtr rfbScreen)
53 {
54 #ifdef VINO_HAVE_GNUTLS
55 gnutls_dh_params_deinit(rfbScreen->dhParams);
56
57 gnutls_anon_free_server_credentials(rfbScreen->anonCredentials);
58
59 gnutls_global_deinit();
60 #endif /* VINO_HAVE_GNUTLS */
61 }
62
63 #ifdef VINO_HAVE_GNUTLS
64 static rfbBool
rfbAuthTLSHandshake(rfbClientPtr cl)65 rfbAuthTLSHandshake(rfbClientPtr cl)
66 {
67 /* TODO: Perform non-anonymous key exchange to prevent man-in-the-middle
68 * attacks. */
69 static const char kx_priority[] = "NORMAL:+ANON-DH";
70 int err;
71
72 gnutls_init(&cl->tlsSession, GNUTLS_SERVER);
73
74 gnutls_set_default_priority(cl->tlsSession);
75 gnutls_priority_set_direct(cl->tlsSession, kx_priority, NULL);
76
77 gnutls_credentials_set(cl->tlsSession,
78 GNUTLS_CRD_ANON,
79 cl->screen->anonCredentials);
80 gnutls_transport_set_ptr(cl->tlsSession, (gnutls_transport_ptr_t) cl->sock);
81
82 err = gnutls_handshake(cl->tlsSession);
83 if (err != GNUTLS_E_SUCCESS && !gnutls_error_is_fatal(err)) {
84 cl->state = RFB_TLS_HANDSHAKE;
85 return FALSE;
86 }
87
88 if (err != GNUTLS_E_SUCCESS) {
89 rfbErr("TLS Handshake failed: %s\n", gnutls_strerror(err));
90 gnutls_deinit (cl->tlsSession);
91 cl->tlsSession = NULL;
92 rfbCloseClient(cl);
93 return FALSE;
94 }
95
96 cl->useTLS = TRUE;
97
98 return TRUE;
99 }
100 #endif /* VINO_HAVE_GNUTLS */
101
102 static rfbBool
rfbAuthClientAuthenticated(rfbClientPtr cl)103 rfbAuthClientAuthenticated(rfbClientPtr cl)
104 {
105 rfbBool accepted = FALSE;
106
107 if (cl->state == RFB_INITIALISATION &&
108 cl->screen->authenticatedClientHook) {
109 switch (cl->screen->authenticatedClientHook(cl)) {
110 case RFB_CLIENT_ON_HOLD:
111 cl->onHold = TRUE;
112 break;
113 case RFB_CLIENT_ACCEPT:
114 accepted = TRUE;
115 break;
116 case RFB_CLIENT_REFUSE:
117 rfbCloseClient(cl);
118 rfbClientConnectionGone(cl);
119 break;
120 }
121 }
122
123 return accepted;
124 }
125
126 /*
127 * rfbAuthNewClient is called when we reach the point of authenticating
128 * a new client. If authentication isn't being used then we simply send
129 * rfbNoAuth. Otherwise we send rfbVncAuth plus the challenge.
130 */
131
132 static void
rfbAuthNewClient3_7(rfbClientPtr cl)133 rfbAuthNewClient3_7(rfbClientPtr cl)
134 {
135 rfbSecurityTypesMsg st;
136 int i;
137
138 cl->state = RFB_SECURITY_TYPE;
139
140 st.nSecurityTypes = cl->screen->nSecurityTypes;
141 for (i = 0; i < st.nSecurityTypes; i++) {
142 rfbLog("Advertising security type %d\n", cl->screen->securityTypes[i]);
143 st.securityTypes[i] = cl->screen->securityTypes[i];
144 }
145
146 if (WriteExact(cl, (char *)&st, st.nSecurityTypes + 1) < 0) {
147 rfbLogPerror("rfbAuthNewClient: write");
148 rfbCloseClient(cl);
149 return;
150 }
151 }
152
153 static void
rfbAuthNewClient3_3(rfbClientPtr cl)154 rfbAuthNewClient3_3(rfbClientPtr cl)
155 {
156 union {
157 uint32_t authType;
158 char buf[4 + CHALLENGESIZE];
159 } auth;
160 int len, i;
161
162 for (i = 0; i < cl->screen->nSecurityTypes; i++)
163 if (cl->screen->securityTypes [i] == rfbVncAuth ||
164 cl->screen->securityTypes [i] == rfbNoAuth)
165 break;
166
167 if (i == cl->screen->nSecurityTypes) {
168 rfbClientConnFailed(cl, "No security type suitable for RFB 3.3 supported");
169 return;
170 }
171
172 switch (cl->screen->securityTypes [i]) {
173 case rfbVncAuth:
174 auth.authType = Swap32IfLE(rfbVncAuth);
175 vncRandomBytes(cl->authChallenge);
176 memcpy(&(auth.buf[4]), (char *)cl->authChallenge, CHALLENGESIZE);
177 len = 4 + CHALLENGESIZE;
178 cl->state = RFB_AUTHENTICATION;
179 break;
180 case rfbNoAuth:
181 auth.authType = Swap32IfLE(rfbNoAuth);
182 len = 4;
183 cl->state = RFB_INITIALISATION;
184 break;
185 default:
186 /* can't be reached */
187 return;
188 }
189
190 if (WriteExact(cl, auth.buf, len) < 0) {
191 rfbLogPerror("rfbAuthNewClient: write");
192 rfbCloseClient(cl);
193 return;
194 }
195
196 rfbAuthClientAuthenticated(cl);
197 }
198
199 void
rfbAuthNewClient(rfbClientPtr cl)200 rfbAuthNewClient(rfbClientPtr cl)
201 {
202 if (cl->minorVersion >= rfbProtocolMinorVersion7)
203 rfbAuthNewClient3_7(cl);
204 else
205 rfbAuthNewClient3_3(cl);
206 }
207
208 void
rfbAuthCleanupClient(rfbClientPtr cl)209 rfbAuthCleanupClient(rfbClientPtr cl)
210 {
211 #ifdef VINO_HAVE_GNUTLS
212 if (cl->tlsSession) {
213 if (cl->sock)
214 gnutls_bye(cl->tlsSession, GNUTLS_SHUT_WR);
215
216 gnutls_deinit(cl->tlsSession);
217 cl->tlsSession = NULL;
218 }
219 #endif /* VINO_HAVE_GNUTLS */
220 }
221
222 #ifdef VINO_HAVE_GNUTLS
223 static void
rfbAuthListAuthTypes(rfbClientPtr cl)224 rfbAuthListAuthTypes(rfbClientPtr cl)
225 {
226 rfbAuthTypesMsg st;
227 int i;
228
229 cl->state = RFB_AUTH_TYPE;
230
231 st.nAuthTypes = cl->screen->nAuthTypes;
232 for (i = 0; i < cl->screen->nAuthTypes; i++) {
233 rfbLog("Advertising authentication type %d\n", cl->screen->authTypes[i]);
234 st.authTypes[i] = cl->screen->authTypes[i];
235 }
236
237 if (WriteExact(cl, (char *)&st, cl->screen->nAuthTypes + 1) < 0) {
238 rfbLogPerror("rfbAuthNewClient: write");
239 rfbCloseClient(cl);
240 return;
241 }
242 }
243 #endif /* VINO_HAVE_GNUTLS */
244
245 void
rfbAuthProcessSecurityTypeMessage(rfbClientPtr cl)246 rfbAuthProcessSecurityTypeMessage(rfbClientPtr cl)
247 {
248 uint8_t securityType;
249 int n, i;
250
251 if ((n = ReadExact(cl, (char *)&securityType, 1)) <= 0) {
252 if (n != 0)
253 rfbLogPerror("rfbAuthProcessSecurityTypeMessage: read");
254 rfbCloseClient(cl);
255 return;
256 }
257
258 rfbLog("Client returned security type %d\n", securityType);
259
260 for (i = 0; i < cl->screen->nSecurityTypes; i++)
261 if (cl->screen->securityTypes[i] == securityType)
262 break;
263
264 if (i == cl->screen->nSecurityTypes) {
265 rfbErr("rfbAuthProcessSecurityTypeMessage: client returned unadvertised security type %d\n",
266 securityType);
267 rfbCloseClient(cl);
268 return;
269 }
270
271 switch (securityType) {
272 #ifdef VINO_HAVE_GNUTLS
273 case rfbTLS:
274 if (!rfbAuthTLSHandshake(cl))
275 return;
276 rfbAuthListAuthTypes(cl);
277 break;
278 #endif
279 case rfbVncAuth:
280 vncRandomBytes(cl->authChallenge);
281 if (WriteExact(cl, (char *)&cl->authChallenge, CHALLENGESIZE) < 0) {
282 rfbLogPerror("rfbAuthProcessSecurityTypeMessage: write");
283 rfbCloseClient(cl);
284 return;
285 }
286 cl->state = RFB_AUTHENTICATION;
287 break;
288 case rfbNoAuth:
289
290 if (cl->minorVersion >= rfbProtocolMinorVersion8)
291 rfbAuthPasswordChecked(cl, RFB_CLIENT_ACCEPT);
292 else {
293 cl->state = RFB_INITIALISATION;
294 if (rfbAuthClientAuthenticated(cl))
295 rfbProcessClientInitMessage(cl);
296 }
297 break;
298 default:
299 /* can't be reached */
300 break;
301 }
302 }
303
304 #ifdef VINO_HAVE_GNUTLS
305 void
rfbAuthProcessTLSHandshake(rfbClientPtr cl)306 rfbAuthProcessTLSHandshake(rfbClientPtr cl)
307 {
308 int err;
309
310 err = gnutls_handshake(cl->tlsSession);
311 if (err != GNUTLS_E_SUCCESS && !gnutls_error_is_fatal(err))
312 return;
313
314 if (err != GNUTLS_E_SUCCESS) {
315 rfbErr("TLS Handshake failed: %s\n", gnutls_strerror(err));
316 gnutls_deinit (cl->tlsSession);
317 cl->tlsSession = NULL;
318 rfbCloseClient(cl);
319 return;
320 }
321
322 cl->useTLS = TRUE;
323
324 rfbAuthListAuthTypes(cl);
325 }
326 #endif /* VINO_HAVE_GNUTLS */
327
328 void
rfbAuthProcessAuthTypeMessage(rfbClientPtr cl)329 rfbAuthProcessAuthTypeMessage(rfbClientPtr cl)
330 {
331 uint8_t authType;
332 int n, i;
333
334 if ((n = ReadExact(cl, (char *)&authType, 1)) <= 0) {
335 if (n != 0)
336 rfbLogPerror("rfbAuthProcessAuthTypeMessage: read");
337 rfbCloseClient(cl);
338 return;
339 }
340
341 rfbLog("Client returned authentication type %d\n", authType);
342
343 for (i = 0; i < cl->screen->nAuthTypes; i++)
344 if (cl->screen->authTypes[i] == authType)
345 break;
346
347 if (i == cl->screen->nAuthTypes) {
348 rfbErr("rfbAuthProcessAuthTypeMessage: client returned unadvertised authentication type %d\n",
349 authType);
350 rfbCloseClient(cl);
351 return;
352 }
353
354 switch (authType) {
355 case rfbVncAuth:
356 vncRandomBytes(cl->authChallenge);
357 if (WriteExact(cl, (char *)&cl->authChallenge, CHALLENGESIZE) < 0) {
358 rfbLogPerror("rfbAuthProcessAuthTypeMessage: write");
359 rfbCloseClient(cl);
360 return;
361 }
362 cl->state = RFB_AUTHENTICATION;
363 break;
364 case rfbNoAuth:
365 cl->state = RFB_INITIALISATION;
366 if (rfbAuthClientAuthenticated(cl))
367 rfbProcessClientInitMessage(cl);
368 break;
369 default:
370 /* can't be reached */
371 break;
372 }
373 }
374
375 /*
376 * rfbAuthProcessClientMessage is called when the client sends its
377 * authentication response.
378 */
379
380 void
rfbAuthProcessClientMessage(rfbClientPtr cl)381 rfbAuthProcessClientMessage(rfbClientPtr cl)
382 {
383 int n;
384 uint8_t response[CHALLENGESIZE];
385 enum rfbNewClientAction result;
386
387 if ((n = ReadExact(cl, (char *)response, CHALLENGESIZE)) <= 0) {
388 if (n != 0)
389 rfbLogPerror("rfbAuthProcessClientMessage: read");
390 rfbCloseClient(cl);
391 return;
392 }
393
394 result = RFB_CLIENT_REFUSE;
395 if (cl->screen->passwordCheck)
396 result = cl->screen->passwordCheck(cl, (const char *)response, CHALLENGESIZE);
397
398 rfbAuthPasswordChecked(cl, result);
399 }
400
401 void
rfbAuthPasswordChecked(rfbClientPtr cl,enum rfbNewClientAction result)402 rfbAuthPasswordChecked(rfbClientPtr cl,
403 enum rfbNewClientAction result)
404 {
405 uint32_t authResult;
406
407 switch (result) {
408 case RFB_CLIENT_ON_HOLD:
409 cl->state = RFB_AUTH_DEFERRED;
410 cl->onHold = TRUE;
411 break;
412 case RFB_CLIENT_ACCEPT:
413 cl->onHold = FALSE;
414 authResult = Swap32IfLE(rfbVncAuthOK);
415
416 if (WriteExact(cl, (char *)&authResult, 4) < 0) {
417 rfbLogPerror("rfbAuthPasswordChecked: write");
418 rfbCloseClient(cl);
419 return;
420 }
421
422 cl->state = RFB_INITIALISATION;
423 rfbAuthClientAuthenticated(cl);
424 break;
425 default:
426 case RFB_CLIENT_REFUSE:
427 rfbErr("rfbAuthPasswordChecked: password check failed\n");
428 authResult = Swap32IfLE(rfbVncAuthFailed);
429
430 if (WriteExact(cl, (char *)&authResult, 4) < 0) {
431 rfbLogPerror("rfbAuthPasswordChecked: write");
432 rfbCloseClient(cl);
433 return;
434 }
435
436 if (cl->minorVersion >= rfbProtocolMinorVersion8) {
437 /* We can't really localize this string, since it has to
438 * be iso8859-1 encoded. However, the string will only be
439 * returned when we're using protocol version 3.8, and we
440 * only advertise support for 3.7, so this only gets used
441 * at all if you have a broken client.
442 */
443 const char errmsg[] = "Password incorrect";
444 uint32_t len, wireLen;
445
446 len = sizeof(errmsg) - 1;
447 wireLen = Swap32IfLE(len);
448 if (WriteExact(cl, (char *)&wireLen, 4) < 0 ||
449 WriteExact(cl, errmsg, len) < 0) {
450 rfbLogPerror("rfbAuthPasswordChecked: write");
451 rfbCloseClient(cl);
452 return;
453 }
454 }
455
456 rfbCloseClient(cl);
457 break;
458 }
459 }
460