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