Commit 8d5d2d4c478c6a853b7334f06253ab73410e9322
1 parent
70848515
VeNCrypt basic TLS support, by Daniel P. Berrange.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3136 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
426 additions
and
8 deletions
Makefile.target
... | ... | @@ -405,6 +405,11 @@ SOUND_HW += fmopl.o adlib.o |
405 | 405 | endif |
406 | 406 | AUDIODRV+= wavcapture.o |
407 | 407 | |
408 | +ifdef CONFIG_VNC_TLS | |
409 | +CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS) | |
410 | +LIBS += $(CONFIG_VNC_TLS_LIBS) | |
411 | +endif | |
412 | + | |
408 | 413 | VL_OBJS += i2c.o smbus.o |
409 | 414 | |
410 | 415 | # SCSI layer | ... | ... |
configure
... | ... | @@ -89,6 +89,7 @@ alsa="no" |
89 | 89 | fmod="no" |
90 | 90 | fmod_lib="" |
91 | 91 | fmod_inc="" |
92 | +vnc_tls="yes" | |
92 | 93 | bsd="no" |
93 | 94 | linux="no" |
94 | 95 | kqemu="no" |
... | ... | @@ -252,6 +253,8 @@ for opt do |
252 | 253 | ;; |
253 | 254 | --fmod-inc=*) fmod_inc="$optarg" |
254 | 255 | ;; |
256 | + --disable-vnc-tls) vnc_tls="no" | |
257 | + ;; | |
255 | 258 | --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; linux_user="no" |
256 | 259 | ;; |
257 | 260 | --disable-slirp) slirp="no" |
... | ... | @@ -362,6 +365,7 @@ echo " --enable-coreaudio enable Coreaudio audio driver" |
362 | 365 | echo " --enable-alsa enable ALSA audio driver" |
363 | 366 | echo " --enable-fmod enable FMOD audio driver" |
364 | 367 | echo " --enable-dsound enable DirectSound audio driver" |
368 | +echo " --disable-vnc-tls disable TLS encryption for VNC server" | |
365 | 369 | echo " --enable-system enable all system emulation targets" |
366 | 370 | echo " --disable-system disable all system emulation targets" |
367 | 371 | echo " --enable-linux-user enable all linux usermode emulation targets" |
... | ... | @@ -589,6 +593,16 @@ else |
589 | 593 | fi # -z $sdl |
590 | 594 | |
591 | 595 | ########################################## |
596 | +# VNC TLS detection | |
597 | +if test "$vnc_tls" = "yes" ; then | |
598 | + `pkg-config gnutls` || vnc_tls="no" | |
599 | +fi | |
600 | +if test "$vnc_tls" = "yes" ; then | |
601 | + vnc_tls_cflags=`pkg-config --cflags gnutls` | |
602 | + vnc_tls_libs=`pkg-config --libs gnutls` | |
603 | +fi | |
604 | + | |
605 | +########################################## | |
592 | 606 | # alsa sound support libraries |
593 | 607 | |
594 | 608 | if test "$alsa" = "yes" ; then |
... | ... | @@ -675,6 +689,11 @@ else |
675 | 689 | fi |
676 | 690 | echo "FMOD support $fmod $fmod_support" |
677 | 691 | echo "OSS support $oss" |
692 | +echo "VNC TLS support $vnc_tls" | |
693 | +if test "$vnc_tls" = "yes" ; then | |
694 | + echo " TLS CFLAGS $vnc_tls_cflags" | |
695 | + echo " TLS LIBS $vnc_tls_libs" | |
696 | +fi | |
678 | 697 | if test -n "$sparc_cpu"; then |
679 | 698 | echo "Target Sparc Arch $sparc_cpu" |
680 | 699 | fi |
... | ... | @@ -847,6 +866,12 @@ if test "$fmod" = "yes" ; then |
847 | 866 | echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak |
848 | 867 | echo "#define CONFIG_FMOD 1" >> $config_h |
849 | 868 | fi |
869 | +if test "$vnc_tls" = "yes" ; then | |
870 | + echo "CONFIG_VNC_TLS=yes" >> $config_mak | |
871 | + echo "CONFIG_VNC_TLS_CFLAGS=$vnc_tls_cflags" >> $config_mak | |
872 | + echo "CONFIG_VNC_TLS_LIBS=$vnc_tls_libs" >> $config_mak | |
873 | + echo "#define CONFIG_VNC_TLS 1" >> $config_h | |
874 | +fi | |
850 | 875 | qemu_version=`head $source_path/VERSION` |
851 | 876 | echo "VERSION=$qemu_version" >>$config_mak |
852 | 877 | echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h | ... | ... |
vnc.c
... | ... | @@ -32,14 +32,27 @@ |
32 | 32 | #include "keymaps.c" |
33 | 33 | #include "d3des.h" |
34 | 34 | |
35 | -// #define _VNC_DEBUG | |
35 | +#if CONFIG_VNC_TLS | |
36 | +#include <gnutls/gnutls.h> | |
37 | +#include <gnutls/x509.h> | |
38 | +#endif /* CONFIG_VNC_TLS */ | |
36 | 39 | |
37 | -#ifdef _VNC_DEBUG | |
40 | +// #define _VNC_DEBUG 1 | |
41 | + | |
42 | +#if _VNC_DEBUG | |
38 | 43 | #define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) |
44 | + | |
45 | +#if CONFIG_VNC_TLS && _VNC_DEBUG >= 2 | |
46 | +/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */ | |
47 | +static void vnc_debug_gnutls_log(int level, const char* str) { | |
48 | + VNC_DEBUG("%d %s", level, str); | |
49 | +} | |
50 | +#endif /* CONFIG_VNC_TLS && _VNC_DEBUG */ | |
39 | 51 | #else |
40 | 52 | #define VNC_DEBUG(fmt, ...) do { } while (0) |
41 | 53 | #endif |
42 | 54 | |
55 | + | |
43 | 56 | typedef struct Buffer |
44 | 57 | { |
45 | 58 | size_t capacity; |
... | ... | @@ -77,6 +90,23 @@ enum { |
77 | 90 | VNC_AUTH_VENCRYPT = 19 |
78 | 91 | }; |
79 | 92 | |
93 | +#if CONFIG_VNC_TLS | |
94 | +enum { | |
95 | + VNC_WIREMODE_CLEAR, | |
96 | + VNC_WIREMODE_TLS, | |
97 | +}; | |
98 | + | |
99 | +enum { | |
100 | + VNC_AUTH_VENCRYPT_PLAIN = 256, | |
101 | + VNC_AUTH_VENCRYPT_TLSNONE = 257, | |
102 | + VNC_AUTH_VENCRYPT_TLSVNC = 258, | |
103 | + VNC_AUTH_VENCRYPT_TLSPLAIN = 259, | |
104 | + VNC_AUTH_VENCRYPT_X509NONE = 260, | |
105 | + VNC_AUTH_VENCRYPT_X509VNC = 261, | |
106 | + VNC_AUTH_VENCRYPT_X509PLAIN = 262, | |
107 | +}; | |
108 | +#endif /* CONFIG_VNC_TLS */ | |
109 | + | |
80 | 110 | struct VncState |
81 | 111 | { |
82 | 112 | QEMUTimer *timer; |
... | ... | @@ -102,8 +132,16 @@ struct VncState |
102 | 132 | char *display; |
103 | 133 | char *password; |
104 | 134 | int auth; |
135 | +#if CONFIG_VNC_TLS | |
136 | + int subauth; | |
137 | +#endif | |
105 | 138 | char challenge[VNC_AUTH_CHALLENGE_SIZE]; |
106 | 139 | |
140 | +#if CONFIG_VNC_TLS | |
141 | + int wiremode; | |
142 | + gnutls_session_t tls_session; | |
143 | +#endif | |
144 | + | |
107 | 145 | Buffer output; |
108 | 146 | Buffer input; |
109 | 147 | kbd_layout_t *kbd_layout; |
... | ... | @@ -579,12 +617,20 @@ static int vnc_client_io_error(VncState *vs, int ret, int last_errno) |
579 | 617 | if (ret == -1 && (last_errno == EINTR || last_errno == EAGAIN)) |
580 | 618 | return 0; |
581 | 619 | |
620 | + VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0); | |
582 | 621 | qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); |
583 | 622 | closesocket(vs->csock); |
584 | 623 | vs->csock = -1; |
585 | 624 | buffer_reset(&vs->input); |
586 | 625 | buffer_reset(&vs->output); |
587 | 626 | vs->need_update = 0; |
627 | +#if CONFIG_VNC_TLS | |
628 | + if (vs->tls_session) { | |
629 | + gnutls_deinit(vs->tls_session); | |
630 | + vs->tls_session = NULL; | |
631 | + } | |
632 | + vs->wiremode = VNC_WIREMODE_CLEAR; | |
633 | +#endif /* CONFIG_VNC_TLS */ | |
588 | 634 | return 0; |
589 | 635 | } |
590 | 636 | return ret; |
... | ... | @@ -600,7 +646,19 @@ static void vnc_client_write(void *opaque) |
600 | 646 | long ret; |
601 | 647 | VncState *vs = opaque; |
602 | 648 | |
603 | - ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0); | |
649 | +#if CONFIG_VNC_TLS | |
650 | + if (vs->tls_session) { | |
651 | + ret = gnutls_write(vs->tls_session, vs->output.buffer, vs->output.offset); | |
652 | + if (ret < 0) { | |
653 | + if (ret == GNUTLS_E_AGAIN) | |
654 | + errno = EAGAIN; | |
655 | + else | |
656 | + errno = EIO; | |
657 | + ret = -1; | |
658 | + } | |
659 | + } else | |
660 | +#endif /* CONFIG_VNC_TLS */ | |
661 | + ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0); | |
604 | 662 | ret = vnc_client_io_error(vs, ret, socket_error()); |
605 | 663 | if (!ret) |
606 | 664 | return; |
... | ... | @@ -626,7 +684,19 @@ static void vnc_client_read(void *opaque) |
626 | 684 | |
627 | 685 | buffer_reserve(&vs->input, 4096); |
628 | 686 | |
629 | - ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0); | |
687 | +#if CONFIG_VNC_TLS | |
688 | + if (vs->tls_session) { | |
689 | + ret = gnutls_read(vs->tls_session, buffer_end(&vs->input), 4096); | |
690 | + if (ret < 0) { | |
691 | + if (ret == GNUTLS_E_AGAIN) | |
692 | + errno = EAGAIN; | |
693 | + else | |
694 | + errno = EIO; | |
695 | + ret = -1; | |
696 | + } | |
697 | + } else | |
698 | +#endif /* CONFIG_VNC_TLS */ | |
699 | + ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0); | |
630 | 700 | ret = vnc_client_io_error(vs, ret, socket_error()); |
631 | 701 | if (!ret) |
632 | 702 | return; |
... | ... | @@ -721,6 +791,41 @@ static uint32_t read_u32(uint8_t *data, size_t offset) |
721 | 791 | (data[offset + 2] << 8) | data[offset + 3]); |
722 | 792 | } |
723 | 793 | |
794 | +#if CONFIG_VNC_TLS | |
795 | +ssize_t vnc_tls_push(gnutls_transport_ptr_t transport, | |
796 | + const void *data, | |
797 | + size_t len) { | |
798 | + struct VncState *vs = (struct VncState *)transport; | |
799 | + int ret; | |
800 | + | |
801 | + retry: | |
802 | + ret = send(vs->csock, data, len, 0); | |
803 | + if (ret < 0) { | |
804 | + if (errno == EINTR) | |
805 | + goto retry; | |
806 | + return -1; | |
807 | + } | |
808 | + return ret; | |
809 | +} | |
810 | + | |
811 | + | |
812 | +ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport, | |
813 | + void *data, | |
814 | + size_t len) { | |
815 | + struct VncState *vs = (struct VncState *)transport; | |
816 | + int ret; | |
817 | + | |
818 | + retry: | |
819 | + ret = recv(vs->csock, data, len, 0); | |
820 | + if (ret < 0) { | |
821 | + if (errno == EINTR) | |
822 | + goto retry; | |
823 | + return -1; | |
824 | + } | |
825 | + return ret; | |
826 | +} | |
827 | +#endif /* CONFIG_VNC_TLS */ | |
828 | + | |
724 | 829 | static void client_cut_text(VncState *vs, size_t len, char *text) |
725 | 830 | { |
726 | 831 | } |
... | ... | @@ -1225,6 +1330,243 @@ static int start_auth_vnc(VncState *vs) |
1225 | 1330 | return 0; |
1226 | 1331 | } |
1227 | 1332 | |
1333 | + | |
1334 | +#if CONFIG_VNC_TLS | |
1335 | +#define DH_BITS 1024 | |
1336 | +static gnutls_dh_params_t dh_params; | |
1337 | + | |
1338 | +static int vnc_tls_initialize(void) | |
1339 | +{ | |
1340 | + static int tlsinitialized = 0; | |
1341 | + | |
1342 | + if (tlsinitialized) | |
1343 | + return 1; | |
1344 | + | |
1345 | + if (gnutls_global_init () < 0) | |
1346 | + return 0; | |
1347 | + | |
1348 | + /* XXX ought to re-generate diffie-hellmen params periodically */ | |
1349 | + if (gnutls_dh_params_init (&dh_params) < 0) | |
1350 | + return 0; | |
1351 | + if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0) | |
1352 | + return 0; | |
1353 | + | |
1354 | +#if _VNC_DEBUG == 2 | |
1355 | + gnutls_global_set_log_level(10); | |
1356 | + gnutls_global_set_log_function(vnc_debug_gnutls_log); | |
1357 | +#endif | |
1358 | + | |
1359 | + tlsinitialized = 1; | |
1360 | + | |
1361 | + return 1; | |
1362 | +} | |
1363 | + | |
1364 | +static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void) | |
1365 | +{ | |
1366 | + gnutls_anon_server_credentials anon_cred; | |
1367 | + int ret; | |
1368 | + | |
1369 | + if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) { | |
1370 | + VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); | |
1371 | + return NULL; | |
1372 | + } | |
1373 | + | |
1374 | + gnutls_anon_set_server_dh_params(anon_cred, dh_params); | |
1375 | + | |
1376 | + return anon_cred; | |
1377 | +} | |
1378 | + | |
1379 | + | |
1380 | +static int start_auth_vencrypt_subauth(VncState *vs) | |
1381 | +{ | |
1382 | + switch (vs->subauth) { | |
1383 | + case VNC_AUTH_VENCRYPT_TLSNONE: | |
1384 | + VNC_DEBUG("Accept TLS auth none\n"); | |
1385 | + vnc_write_u32(vs, 0); /* Accept auth completion */ | |
1386 | + vnc_read_when(vs, protocol_client_init, 1); | |
1387 | + break; | |
1388 | + | |
1389 | + case VNC_AUTH_VENCRYPT_TLSVNC: | |
1390 | + VNC_DEBUG("Start TLS auth VNC\n"); | |
1391 | + return start_auth_vnc(vs); | |
1392 | + | |
1393 | + default: /* Should not be possible, but just in case */ | |
1394 | + VNC_DEBUG("Reject auth %d\n", vs->auth); | |
1395 | + vnc_write_u8(vs, 1); | |
1396 | + if (vs->minor >= 8) { | |
1397 | + static const char err[] = "Unsupported authentication type"; | |
1398 | + vnc_write_u32(vs, sizeof(err)); | |
1399 | + vnc_write(vs, err, sizeof(err)); | |
1400 | + } | |
1401 | + vnc_client_error(vs); | |
1402 | + } | |
1403 | + | |
1404 | + return 0; | |
1405 | +} | |
1406 | + | |
1407 | +static void vnc_handshake_io(void *opaque); | |
1408 | + | |
1409 | +static int vnc_continue_handshake(struct VncState *vs) { | |
1410 | + int ret; | |
1411 | + | |
1412 | + if ((ret = gnutls_handshake(vs->tls_session)) < 0) { | |
1413 | + if (!gnutls_error_is_fatal(ret)) { | |
1414 | + VNC_DEBUG("Handshake interrupted (blocking)\n"); | |
1415 | + if (!gnutls_record_get_direction(vs->tls_session)) | |
1416 | + qemu_set_fd_handler(vs->csock, vnc_handshake_io, NULL, vs); | |
1417 | + else | |
1418 | + qemu_set_fd_handler(vs->csock, NULL, vnc_handshake_io, vs); | |
1419 | + return 0; | |
1420 | + } | |
1421 | + VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret)); | |
1422 | + vnc_client_error(vs); | |
1423 | + return -1; | |
1424 | + } | |
1425 | + | |
1426 | + VNC_DEBUG("Handshake done, switching to TLS data mode\n"); | |
1427 | + vs->wiremode = VNC_WIREMODE_TLS; | |
1428 | + qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs); | |
1429 | + | |
1430 | + return start_auth_vencrypt_subauth(vs); | |
1431 | +} | |
1432 | + | |
1433 | +static void vnc_handshake_io(void *opaque) { | |
1434 | + struct VncState *vs = (struct VncState *)opaque; | |
1435 | + | |
1436 | + VNC_DEBUG("Handshake IO continue\n"); | |
1437 | + vnc_continue_handshake(vs); | |
1438 | +} | |
1439 | + | |
1440 | +static int vnc_start_tls(struct VncState *vs) { | |
1441 | + static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; | |
1442 | + static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 }; | |
1443 | + static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0}; | |
1444 | + gnutls_anon_server_credentials anon_cred = NULL; | |
1445 | + | |
1446 | + VNC_DEBUG("Do TLS setup\n"); | |
1447 | + if (vnc_tls_initialize() < 0) { | |
1448 | + VNC_DEBUG("Failed to init TLS\n"); | |
1449 | + vnc_client_error(vs); | |
1450 | + return -1; | |
1451 | + } | |
1452 | + if (vs->tls_session == NULL) { | |
1453 | + if (gnutls_init(&vs->tls_session, GNUTLS_SERVER) < 0) { | |
1454 | + vnc_client_error(vs); | |
1455 | + return -1; | |
1456 | + } | |
1457 | + | |
1458 | + if (gnutls_set_default_priority(vs->tls_session) < 0) { | |
1459 | + gnutls_deinit(vs->tls_session); | |
1460 | + vs->tls_session = NULL; | |
1461 | + vnc_client_error(vs); | |
1462 | + return -1; | |
1463 | + } | |
1464 | + | |
1465 | + if (gnutls_kx_set_priority(vs->tls_session, kx_anon) < 0) { | |
1466 | + gnutls_deinit(vs->tls_session); | |
1467 | + vs->tls_session = NULL; | |
1468 | + vnc_client_error(vs); | |
1469 | + return -1; | |
1470 | + } | |
1471 | + | |
1472 | + if (gnutls_certificate_type_set_priority(vs->tls_session, cert_type_priority) < 0) { | |
1473 | + gnutls_deinit(vs->tls_session); | |
1474 | + vs->tls_session = NULL; | |
1475 | + vnc_client_error(vs); | |
1476 | + return -1; | |
1477 | + } | |
1478 | + | |
1479 | + if (gnutls_protocol_set_priority(vs->tls_session, protocol_priority) < 0) { | |
1480 | + gnutls_deinit(vs->tls_session); | |
1481 | + vs->tls_session = NULL; | |
1482 | + vnc_client_error(vs); | |
1483 | + return -1; | |
1484 | + } | |
1485 | + | |
1486 | + anon_cred = vnc_tls_initialize_anon_cred(); | |
1487 | + if (!anon_cred) { | |
1488 | + gnutls_deinit(vs->tls_session); | |
1489 | + vs->tls_session = NULL; | |
1490 | + vnc_client_error(vs); | |
1491 | + return -1; | |
1492 | + } | |
1493 | + if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) { | |
1494 | + gnutls_deinit(vs->tls_session); | |
1495 | + vs->tls_session = NULL; | |
1496 | + gnutls_anon_free_server_credentials(anon_cred); | |
1497 | + vnc_client_error(vs); | |
1498 | + return -1; | |
1499 | + } | |
1500 | + | |
1501 | + gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs); | |
1502 | + gnutls_transport_set_push_function(vs->tls_session, vnc_tls_push); | |
1503 | + gnutls_transport_set_pull_function(vs->tls_session, vnc_tls_pull); | |
1504 | + } | |
1505 | + | |
1506 | + VNC_DEBUG("Start TLS handshake process\n"); | |
1507 | + return vnc_continue_handshake(vs); | |
1508 | +} | |
1509 | + | |
1510 | +static int protocol_client_vencrypt_auth(VncState *vs, char *data, size_t len) | |
1511 | +{ | |
1512 | + int auth = read_u32(data, 0); | |
1513 | + | |
1514 | + if (auth != vs->subauth) { | |
1515 | + VNC_DEBUG("Rejecting auth %d\n", auth); | |
1516 | + vnc_write_u8(vs, 0); /* Reject auth */ | |
1517 | + vnc_flush(vs); | |
1518 | + vnc_client_error(vs); | |
1519 | + } else { | |
1520 | + VNC_DEBUG("Accepting auth %d, starting handshake\n", auth); | |
1521 | + vnc_write_u8(vs, 1); /* Accept auth */ | |
1522 | + vnc_flush(vs); | |
1523 | + | |
1524 | + if (vnc_start_tls(vs) < 0) { | |
1525 | + VNC_DEBUG("Failed to complete TLS\n"); | |
1526 | + return 0; | |
1527 | + } | |
1528 | + | |
1529 | + if (vs->wiremode == VNC_WIREMODE_TLS) { | |
1530 | + VNC_DEBUG("Starting VeNCrypt subauth\n"); | |
1531 | + return start_auth_vencrypt_subauth(vs); | |
1532 | + } else { | |
1533 | + VNC_DEBUG("TLS handshake blocked\n"); | |
1534 | + return 0; | |
1535 | + } | |
1536 | + } | |
1537 | + return 0; | |
1538 | +} | |
1539 | + | |
1540 | +static int protocol_client_vencrypt_init(VncState *vs, char *data, size_t len) | |
1541 | +{ | |
1542 | + if (data[0] != 0 || | |
1543 | + data[1] != 2) { | |
1544 | + VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]); | |
1545 | + vnc_write_u8(vs, 1); /* Reject version */ | |
1546 | + vnc_flush(vs); | |
1547 | + vnc_client_error(vs); | |
1548 | + } else { | |
1549 | + VNC_DEBUG("Sending allowed auth %d\n", vs->subauth); | |
1550 | + vnc_write_u8(vs, 0); /* Accept version */ | |
1551 | + vnc_write_u8(vs, 1); /* Number of sub-auths */ | |
1552 | + vnc_write_u32(vs, vs->subauth); /* The supported auth */ | |
1553 | + vnc_flush(vs); | |
1554 | + vnc_read_when(vs, protocol_client_vencrypt_auth, 4); | |
1555 | + } | |
1556 | + return 0; | |
1557 | +} | |
1558 | + | |
1559 | +static int start_auth_vencrypt(VncState *vs) | |
1560 | +{ | |
1561 | + /* Send VeNCrypt version 0.2 */ | |
1562 | + vnc_write_u8(vs, 0); | |
1563 | + vnc_write_u8(vs, 2); | |
1564 | + | |
1565 | + vnc_read_when(vs, protocol_client_vencrypt_init, 2); | |
1566 | + return 0; | |
1567 | +} | |
1568 | +#endif /* CONFIG_VNC_TLS */ | |
1569 | + | |
1228 | 1570 | static int protocol_client_auth(VncState *vs, char *data, size_t len) |
1229 | 1571 | { |
1230 | 1572 | /* We only advertise 1 auth scheme at a time, so client |
... | ... | @@ -1251,6 +1593,12 @@ static int protocol_client_auth(VncState *vs, char *data, size_t len) |
1251 | 1593 | VNC_DEBUG("Start VNC auth\n"); |
1252 | 1594 | return start_auth_vnc(vs); |
1253 | 1595 | |
1596 | +#if CONFIG_VNC_TLS | |
1597 | + case VNC_AUTH_VENCRYPT: | |
1598 | + VNC_DEBUG("Accept VeNCrypt auth\n");; | |
1599 | + return start_auth_vencrypt(vs); | |
1600 | +#endif /* CONFIG_VNC_TLS */ | |
1601 | + | |
1254 | 1602 | default: /* Should not be possible, but just in case */ |
1255 | 1603 | VNC_DEBUG("Reject auth %d\n", vs->auth); |
1256 | 1604 | vnc_write_u8(vs, 1); |
... | ... | @@ -1331,6 +1679,7 @@ static void vnc_listen_read(void *opaque) |
1331 | 1679 | |
1332 | 1680 | vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); |
1333 | 1681 | if (vs->csock != -1) { |
1682 | + VNC_DEBUG("New client on socket %d\n", vs->csock); | |
1334 | 1683 | socket_set_nonblock(vs->csock); |
1335 | 1684 | qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque); |
1336 | 1685 | vnc_write(vs, "RFB 003.008\n", 12); |
... | ... | @@ -1404,8 +1753,18 @@ void vnc_display_close(DisplayState *ds) |
1404 | 1753 | buffer_reset(&vs->input); |
1405 | 1754 | buffer_reset(&vs->output); |
1406 | 1755 | vs->need_update = 0; |
1756 | +#if CONFIG_VNC_TLS | |
1757 | + if (vs->tls_session) { | |
1758 | + gnutls_deinit(vs->tls_session); | |
1759 | + vs->tls_session = NULL; | |
1760 | + } | |
1761 | + vs->wiremode = VNC_WIREMODE_CLEAR; | |
1762 | +#endif /* CONFIG_VNC_TLS */ | |
1407 | 1763 | } |
1408 | 1764 | vs->auth = VNC_AUTH_INVALID; |
1765 | +#if CONFIG_VNC_TLS | |
1766 | + vs->subauth = VNC_AUTH_INVALID; | |
1767 | +#endif | |
1409 | 1768 | } |
1410 | 1769 | |
1411 | 1770 | int vnc_display_password(DisplayState *ds, const char *password) |
... | ... | @@ -1437,6 +1796,9 @@ int vnc_display_open(DisplayState *ds, const char *display) |
1437 | 1796 | VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; |
1438 | 1797 | const char *options; |
1439 | 1798 | int password = 0; |
1799 | +#if CONFIG_VNC_TLS | |
1800 | + int tls = 0; | |
1801 | +#endif | |
1440 | 1802 | |
1441 | 1803 | vnc_display_close(ds); |
1442 | 1804 | if (strcmp(display, "none") == 0) |
... | ... | @@ -1450,14 +1812,40 @@ int vnc_display_open(DisplayState *ds, const char *display) |
1450 | 1812 | options++; |
1451 | 1813 | if (strncmp(options, "password", 8) == 0) |
1452 | 1814 | password = 1; /* Require password auth */ |
1815 | +#if CONFIG_VNC_TLS | |
1816 | + else if (strncmp(options, "tls", 3) == 0) | |
1817 | + tls = 1; /* Require TLS */ | |
1818 | +#endif | |
1453 | 1819 | } |
1454 | 1820 | |
1455 | 1821 | if (password) { |
1456 | - VNC_DEBUG("Initializing VNC server with password auth\n"); | |
1457 | - vs->auth = VNC_AUTH_VNC; | |
1822 | +#if CONFIG_VNC_TLS | |
1823 | + if (tls) { | |
1824 | + VNC_DEBUG("Initializing VNC server with TLS password auth\n"); | |
1825 | + vs->auth = VNC_AUTH_VENCRYPT; | |
1826 | + vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC; | |
1827 | + } else { | |
1828 | +#endif | |
1829 | + VNC_DEBUG("Initializing VNC server with password auth\n"); | |
1830 | + vs->auth = VNC_AUTH_VNC; | |
1831 | +#if CONFIG_VNC_TLS | |
1832 | + vs->subauth = VNC_AUTH_INVALID; | |
1833 | + } | |
1834 | +#endif | |
1458 | 1835 | } else { |
1459 | - VNC_DEBUG("Initializing VNC server with no auth\n"); | |
1460 | - vs->auth = VNC_AUTH_NONE; | |
1836 | +#if CONFIG_VNC_TLS | |
1837 | + if (tls) { | |
1838 | + VNC_DEBUG("Initializing VNC server with TLS no auth\n"); | |
1839 | + vs->auth = VNC_AUTH_VENCRYPT; | |
1840 | + vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE; | |
1841 | + } else { | |
1842 | +#endif | |
1843 | + VNC_DEBUG("Initializing VNC server with no auth\n"); | |
1844 | + vs->auth = VNC_AUTH_NONE; | |
1845 | +#if CONFIG_VNC_TLS | |
1846 | + vs->subauth = VNC_AUTH_INVALID; | |
1847 | + } | |
1848 | +#endif | |
1461 | 1849 | } |
1462 | 1850 | #ifndef _WIN32 |
1463 | 1851 | if (strstart(display, "unix:", &p)) { | ... | ... |