ia64/xen-unstable

changeset 16271:f7026f931e60

qemu vnc auth 3/4: Add VNC auth support from upstream QEMU

This patch adds in the upstream QEMU VNC authentication code. This
spports the previous VNC password auth scheme, as well as the VeNCrypt
protocol extension. The latter allows for performing a TLS handshake,
and client verification of the server identify using x509
certificates. It is also possible for the server to request a client
certificate and validate that as a simple auth scheme. The code
depends on GNU TLS for SSL APIs, and the configure script will
auto-detect this.

The image.py code is changed to deal with the new syntax for the -vnc
option. In particular password authentication is now enabled by
giving the 'password' flag,

eg -vnc 0.0.0:1,password

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
author Keir Fraser <keir@xensource.com>
date Tue Oct 30 09:30:49 2007 +0000 (2007-10-30)
parents 5cc6a30faf69
children dc3fcd5dd4eb
files tools/ioemu/Makefile.target tools/ioemu/configure tools/ioemu/d3des.c tools/ioemu/d3des.h tools/ioemu/monitor.c tools/ioemu/vl.c tools/ioemu/vl.h tools/ioemu/vnc.c tools/ioemu/xenstore.c tools/python/xen/xend/image.py
line diff
     1.1 --- a/tools/ioemu/Makefile.target	Tue Oct 30 09:24:17 2007 +0000
     1.2 +++ b/tools/ioemu/Makefile.target	Tue Oct 30 09:30:49 2007 +0000
     1.3 @@ -387,6 +387,11 @@ SOUND_HW += fmopl.o adlib.o
     1.4  endif
     1.5  AUDIODRV+= wavcapture.o
     1.6  
     1.7 +ifdef CONFIG_VNC_TLS
     1.8 +CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
     1.9 +LIBS += $(CONFIG_VNC_TLS_LIBS)
    1.10 +endif
    1.11 +
    1.12  # SCSI layer
    1.13  VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
    1.14  
    1.15 @@ -456,7 +461,7 @@ endif
    1.16  ifdef CONFIG_SDL
    1.17  VL_OBJS+=sdl.o x_keymap.o
    1.18  endif
    1.19 -VL_OBJS+=vnc.o
    1.20 +VL_OBJS+=vnc.o d3des.o
    1.21  ifdef CONFIG_COCOA
    1.22  VL_OBJS+=cocoa.o
    1.23  COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit
    1.24 @@ -514,7 +519,7 @@ cocoa.o: cocoa.m
    1.25  sdl.o: sdl.c keymaps.c sdl_keysym.h
    1.26  	$(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $<
    1.27  
    1.28 -vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h
    1.29 +vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h d3des.c d3des.h
    1.30  	$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
    1.31  
    1.32  sdlaudio.o: sdlaudio.c
     2.1 --- a/tools/ioemu/configure	Tue Oct 30 09:24:17 2007 +0000
     2.2 +++ b/tools/ioemu/configure	Tue Oct 30 09:30:49 2007 +0000
     2.3 @@ -87,6 +87,7 @@ alsa="no"
     2.4  fmod="no"
     2.5  fmod_lib=""
     2.6  fmod_inc=""
     2.7 +vnc_tls="yes"
     2.8  bsd="no"
     2.9  linux="no"
    2.10  kqemu="no"
    2.11 @@ -225,6 +226,8 @@ for opt do
    2.12    ;;
    2.13    --fmod-inc=*) fmod_inc="$optarg"
    2.14    ;;
    2.15 +  --disable-vnc-tls) vnc_tls="no"
    2.16 +  ;;
    2.17    --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; user="no"
    2.18    ;;
    2.19    --disable-slirp) slirp="no"
    2.20 @@ -292,6 +295,7 @@ echo "  --enable-coreaudio       enable 
    2.21  echo "  --enable-alsa            enable ALSA audio driver"
    2.22  echo "  --enable-fmod            enable FMOD audio driver"
    2.23  echo "  --enabled-dsound         enable DirectSound audio driver"
    2.24 +echo "  --disable-vnc-tls        disable TLS encryption for VNC server"
    2.25  echo "  --enable-system          enable all system emulation targets"
    2.26  echo "  --disable-system         disable all system emulation targets"
    2.27  echo "  --enable-linux-user      enable all linux usermode emulation targets"
    2.28 @@ -410,6 +414,18 @@ if test "$solaris" = "yes" ; then
    2.29    fi
    2.30  fi 
    2.31  
    2.32 +##########################################
    2.33 +
    2.34 +# VNC TLS detection
    2.35 +if test "$vnc_tls" = "yes" ; then
    2.36 +  `pkg-config gnutls` || vnc_tls="no"
    2.37 +fi
    2.38 +if test "$vnc_tls" = "yes" ; then
    2.39 +  vnc_tls_cflags=`pkg-config --cflags gnutls`
    2.40 +  vnc_tls_libs=`pkg-config --libs gnutls`
    2.41 +fi
    2.42 +
    2.43 +##########################################
    2.44  
    2.45  if test -z "$target_list" ; then
    2.46  # these targets are portable
    2.47 @@ -772,6 +788,12 @@ if test "$fmod" = "yes" ; then
    2.48    echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak
    2.49    echo "#define CONFIG_FMOD 1" >> $config_h
    2.50  fi
    2.51 +if test "$vnc_tls" = "yes" ; then
    2.52 +  echo "CONFIG_VNC_TLS=yes" >> $config_mak
    2.53 +  echo "CONFIG_VNC_TLS_CFLAGS=$vnc_tls_cflags" >> $config_mak
    2.54 +  echo "CONFIG_VNC_TLS_LIBS=$vnc_tls_libs" >> $config_mak
    2.55 +  echo "#define CONFIG_VNC_TLS 1" >> $config_h
    2.56 +fi
    2.57  qemu_version=`head $source_path/VERSION`
    2.58  echo "VERSION=$qemu_version" >>$config_mak
    2.59  echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h
    2.60 @@ -999,4 +1021,10 @@ if test "$source_path_used" = "yes" ; th
    2.61      done
    2.62  fi
    2.63  
    2.64 +echo "VNC TLS support   $vnc_tls"
    2.65 +if test "$vnc_tls" = "yes" ; then
    2.66 +    echo "    TLS CFLAGS    $vnc_tls_cflags"
    2.67 +    echo "    TLS LIBS      $vnc_tls_libs"
    2.68 +fi
    2.69 +
    2.70  rm -f $TMPO $TMPC $TMPE $TMPS
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/ioemu/d3des.c	Tue Oct 30 09:30:49 2007 +0000
     3.3 @@ -0,0 +1,434 @@
     3.4 +/*
     3.5 + * This is D3DES (V5.09) by Richard Outerbridge with the double and
     3.6 + * triple-length support removed for use in VNC.  Also the bytebit[] array
     3.7 + * has been reversed so that the most significant bit in each byte of the
     3.8 + * key is ignored, not the least significant.
     3.9 + *
    3.10 + * These changes are:
    3.11 + *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
    3.12 + *
    3.13 + * This software is distributed in the hope that it will be useful,
    3.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    3.16 + */
    3.17 +
    3.18 +/* D3DES (V5.09) -
    3.19 + *
    3.20 + * A portable, public domain, version of the Data Encryption Standard.
    3.21 + *
    3.22 + * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
    3.23 + * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
    3.24 + * code;  Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
    3.25 + * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
    3.26 + * for humouring me on.
    3.27 + *
    3.28 + * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
    3.29 + * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
    3.30 + */
    3.31 +
    3.32 +#include "d3des.h"
    3.33 +
    3.34 +static void scrunch(unsigned char *, unsigned long *);
    3.35 +static void unscrun(unsigned long *, unsigned char *);
    3.36 +static void desfunc(unsigned long *, unsigned long *);
    3.37 +static void cookey(unsigned long *);
    3.38 +
    3.39 +static unsigned long KnL[32] = { 0L };
    3.40 +
    3.41 +static unsigned short bytebit[8]	= {
    3.42 +	01, 02, 04, 010, 020, 040, 0100, 0200 };
    3.43 +
    3.44 +static unsigned long bigbyte[24] = {
    3.45 +	0x800000L,	0x400000L,	0x200000L,	0x100000L,
    3.46 +	0x80000L,	0x40000L,	0x20000L,	0x10000L,
    3.47 +	0x8000L,	0x4000L,	0x2000L,	0x1000L,
    3.48 +	0x800L, 	0x400L, 	0x200L, 	0x100L,
    3.49 +	0x80L,		0x40L,		0x20L,		0x10L,
    3.50 +	0x8L,		0x4L,		0x2L,		0x1L	};
    3.51 +
    3.52 +/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
    3.53 +
    3.54 +static unsigned char pc1[56] = {
    3.55 +	56, 48, 40, 32, 24, 16,  8,	 0, 57, 49, 41, 33, 25, 17,
    3.56 +	 9,  1, 58, 50, 42, 34, 26,	18, 10,  2, 59, 51, 43, 35,
    3.57 +	62, 54, 46, 38, 30, 22, 14,	 6, 61, 53, 45, 37, 29, 21,
    3.58 +	13,  5, 60, 52, 44, 36, 28,	20, 12,  4, 27, 19, 11,  3 };
    3.59 +
    3.60 +static unsigned char totrot[16] = {
    3.61 +	1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
    3.62 +
    3.63 +static unsigned char pc2[48] = {
    3.64 +	13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9,
    3.65 +	22, 18, 11,  3, 25,  7, 15,  6, 26, 19, 12,  1,
    3.66 +	40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
    3.67 +	43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
    3.68 +
    3.69 +void deskey(key, edf)	/* Thanks to James Gillogly & Phil Karn! */
    3.70 +unsigned char *key;
    3.71 +int edf;
    3.72 +{
    3.73 +	register int i, j, l, m, n;
    3.74 +	unsigned char pc1m[56], pcr[56];
    3.75 +	unsigned long kn[32];
    3.76 +
    3.77 +	for ( j = 0; j < 56; j++ ) {
    3.78 +		l = pc1[j];
    3.79 +		m = l & 07;
    3.80 +		pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
    3.81 +		}
    3.82 +	for( i = 0; i < 16; i++ ) {
    3.83 +		if( edf == DE1 ) m = (15 - i) << 1;
    3.84 +		else m = i << 1;
    3.85 +		n = m + 1;
    3.86 +		kn[m] = kn[n] = 0L;
    3.87 +		for( j = 0; j < 28; j++ ) {
    3.88 +			l = j + totrot[i];
    3.89 +			if( l < 28 ) pcr[j] = pc1m[l];
    3.90 +			else pcr[j] = pc1m[l - 28];
    3.91 +			}
    3.92 +		for( j = 28; j < 56; j++ ) {
    3.93 +		    l = j + totrot[i];
    3.94 +		    if( l < 56 ) pcr[j] = pc1m[l];
    3.95 +		    else pcr[j] = pc1m[l - 28];
    3.96 +		    }
    3.97 +		for( j = 0; j < 24; j++ ) {
    3.98 +			if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
    3.99 +			if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
   3.100 +			}
   3.101 +		}
   3.102 +	cookey(kn);
   3.103 +	return;
   3.104 +	}
   3.105 +
   3.106 +static void cookey(raw1)
   3.107 +register unsigned long *raw1;
   3.108 +{
   3.109 +	register unsigned long *cook, *raw0;
   3.110 +	unsigned long dough[32];
   3.111 +	register int i;
   3.112 +
   3.113 +	cook = dough;
   3.114 +	for( i = 0; i < 16; i++, raw1++ ) {
   3.115 +		raw0 = raw1++;
   3.116 +		*cook	 = (*raw0 & 0x00fc0000L) << 6;
   3.117 +		*cook	|= (*raw0 & 0x00000fc0L) << 10;
   3.118 +		*cook	|= (*raw1 & 0x00fc0000L) >> 10;
   3.119 +		*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
   3.120 +		*cook	 = (*raw0 & 0x0003f000L) << 12;
   3.121 +		*cook	|= (*raw0 & 0x0000003fL) << 16;
   3.122 +		*cook	|= (*raw1 & 0x0003f000L) >> 4;
   3.123 +		*cook++ |= (*raw1 & 0x0000003fL);
   3.124 +		}
   3.125 +	usekey(dough);
   3.126 +	return;
   3.127 +	}
   3.128 +
   3.129 +void cpkey(into)
   3.130 +register unsigned long *into;
   3.131 +{
   3.132 +	register unsigned long *from, *endp;
   3.133 +
   3.134 +	from = KnL, endp = &KnL[32];
   3.135 +	while( from < endp ) *into++ = *from++;
   3.136 +	return;
   3.137 +	}
   3.138 +
   3.139 +void usekey(from)
   3.140 +register unsigned long *from;
   3.141 +{
   3.142 +	register unsigned long *to, *endp;
   3.143 +
   3.144 +	to = KnL, endp = &KnL[32];
   3.145 +	while( to < endp ) *to++ = *from++;
   3.146 +	return;
   3.147 +	}
   3.148 +
   3.149 +void des(inblock, outblock)
   3.150 +unsigned char *inblock, *outblock;
   3.151 +{
   3.152 +	unsigned long work[2];
   3.153 +
   3.154 +	scrunch(inblock, work);
   3.155 +	desfunc(work, KnL);
   3.156 +	unscrun(work, outblock);
   3.157 +	return;
   3.158 +	}
   3.159 +
   3.160 +static void scrunch(outof, into)
   3.161 +register unsigned char *outof;
   3.162 +register unsigned long *into;
   3.163 +{
   3.164 +	*into	 = (*outof++ & 0xffL) << 24;
   3.165 +	*into	|= (*outof++ & 0xffL) << 16;
   3.166 +	*into	|= (*outof++ & 0xffL) << 8;
   3.167 +	*into++ |= (*outof++ & 0xffL);
   3.168 +	*into	 = (*outof++ & 0xffL) << 24;
   3.169 +	*into	|= (*outof++ & 0xffL) << 16;
   3.170 +	*into	|= (*outof++ & 0xffL) << 8;
   3.171 +	*into	|= (*outof   & 0xffL);
   3.172 +	return;
   3.173 +	}
   3.174 +
   3.175 +static void unscrun(outof, into)
   3.176 +register unsigned long *outof;
   3.177 +register unsigned char *into;
   3.178 +{
   3.179 +	*into++ = (unsigned char)((*outof >> 24) & 0xffL);
   3.180 +	*into++ = (unsigned char)((*outof >> 16) & 0xffL);
   3.181 +	*into++ = (unsigned char)((*outof >>  8) & 0xffL);
   3.182 +	*into++ = (unsigned char)(*outof++	 & 0xffL);
   3.183 +	*into++ = (unsigned char)((*outof >> 24) & 0xffL);
   3.184 +	*into++ = (unsigned char)((*outof >> 16) & 0xffL);
   3.185 +	*into++ = (unsigned char)((*outof >>  8) & 0xffL);
   3.186 +	*into	=  (unsigned char)(*outof	 & 0xffL);
   3.187 +	return;
   3.188 +	}
   3.189 +
   3.190 +static unsigned long SP1[64] = {
   3.191 +	0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
   3.192 +	0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
   3.193 +	0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
   3.194 +	0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
   3.195 +	0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
   3.196 +	0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
   3.197 +	0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
   3.198 +	0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
   3.199 +	0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
   3.200 +	0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
   3.201 +	0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
   3.202 +	0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
   3.203 +	0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
   3.204 +	0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
   3.205 +	0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
   3.206 +	0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
   3.207 +
   3.208 +static unsigned long SP2[64] = {
   3.209 +	0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
   3.210 +	0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
   3.211 +	0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
   3.212 +	0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
   3.213 +	0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
   3.214 +	0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
   3.215 +	0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
   3.216 +	0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
   3.217 +	0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
   3.218 +	0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
   3.219 +	0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
   3.220 +	0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
   3.221 +	0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
   3.222 +	0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
   3.223 +	0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
   3.224 +	0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
   3.225 +
   3.226 +static unsigned long SP3[64] = {
   3.227 +	0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
   3.228 +	0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
   3.229 +	0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
   3.230 +	0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
   3.231 +	0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
   3.232 +	0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
   3.233 +	0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
   3.234 +	0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
   3.235 +	0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
   3.236 +	0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
   3.237 +	0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
   3.238 +	0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
   3.239 +	0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
   3.240 +	0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
   3.241 +	0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
   3.242 +	0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
   3.243 +
   3.244 +static unsigned long SP4[64] = {
   3.245 +	0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
   3.246 +	0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
   3.247 +	0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
   3.248 +	0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
   3.249 +	0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
   3.250 +	0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
   3.251 +	0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
   3.252 +	0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
   3.253 +	0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
   3.254 +	0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
   3.255 +	0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
   3.256 +	0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
   3.257 +	0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
   3.258 +	0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
   3.259 +	0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
   3.260 +	0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
   3.261 +
   3.262 +static unsigned long SP5[64] = {
   3.263 +	0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
   3.264 +	0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
   3.265 +	0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
   3.266 +	0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
   3.267 +	0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
   3.268 +	0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
   3.269 +	0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
   3.270 +	0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
   3.271 +	0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
   3.272 +	0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
   3.273 +	0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
   3.274 +	0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
   3.275 +	0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
   3.276 +	0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
   3.277 +	0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
   3.278 +	0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
   3.279 +
   3.280 +static unsigned long SP6[64] = {
   3.281 +	0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
   3.282 +	0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
   3.283 +	0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
   3.284 +	0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
   3.285 +	0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
   3.286 +	0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
   3.287 +	0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
   3.288 +	0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
   3.289 +	0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
   3.290 +	0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
   3.291 +	0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
   3.292 +	0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
   3.293 +	0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
   3.294 +	0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
   3.295 +	0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
   3.296 +	0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
   3.297 +
   3.298 +static unsigned long SP7[64] = {
   3.299 +	0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
   3.300 +	0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
   3.301 +	0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
   3.302 +	0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
   3.303 +	0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
   3.304 +	0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
   3.305 +	0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
   3.306 +	0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
   3.307 +	0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
   3.308 +	0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
   3.309 +	0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
   3.310 +	0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
   3.311 +	0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
   3.312 +	0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
   3.313 +	0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
   3.314 +	0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
   3.315 +
   3.316 +static unsigned long SP8[64] = {
   3.317 +	0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
   3.318 +	0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
   3.319 +	0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
   3.320 +	0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
   3.321 +	0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
   3.322 +	0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
   3.323 +	0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
   3.324 +	0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
   3.325 +	0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
   3.326 +	0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
   3.327 +	0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
   3.328 +	0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
   3.329 +	0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
   3.330 +	0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
   3.331 +	0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
   3.332 +	0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
   3.333 +
   3.334 +static void desfunc(block, keys)
   3.335 +register unsigned long *block, *keys;
   3.336 +{
   3.337 +	register unsigned long fval, work, right, leftt;
   3.338 +	register int round;
   3.339 +
   3.340 +	leftt = block[0];
   3.341 +	right = block[1];
   3.342 +	work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
   3.343 +	right ^= work;
   3.344 +	leftt ^= (work << 4);
   3.345 +	work = ((leftt >> 16) ^ right) & 0x0000ffffL;
   3.346 +	right ^= work;
   3.347 +	leftt ^= (work << 16);
   3.348 +	work = ((right >> 2) ^ leftt) & 0x33333333L;
   3.349 +	leftt ^= work;
   3.350 +	right ^= (work << 2);
   3.351 +	work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
   3.352 +	leftt ^= work;
   3.353 +	right ^= (work << 8);
   3.354 +	right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
   3.355 +	work = (leftt ^ right) & 0xaaaaaaaaL;
   3.356 +	leftt ^= work;
   3.357 +	right ^= work;
   3.358 +	leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
   3.359 +
   3.360 +	for( round = 0; round < 8; round++ ) {
   3.361 +		work  = (right << 28) | (right >> 4);
   3.362 +		work ^= *keys++;
   3.363 +		fval  = SP7[ work		 & 0x3fL];
   3.364 +		fval |= SP5[(work >>  8) & 0x3fL];
   3.365 +		fval |= SP3[(work >> 16) & 0x3fL];
   3.366 +		fval |= SP1[(work >> 24) & 0x3fL];
   3.367 +		work  = right ^ *keys++;
   3.368 +		fval |= SP8[ work		 & 0x3fL];
   3.369 +		fval |= SP6[(work >>  8) & 0x3fL];
   3.370 +		fval |= SP4[(work >> 16) & 0x3fL];
   3.371 +		fval |= SP2[(work >> 24) & 0x3fL];
   3.372 +		leftt ^= fval;
   3.373 +		work  = (leftt << 28) | (leftt >> 4);
   3.374 +		work ^= *keys++;
   3.375 +		fval  = SP7[ work		 & 0x3fL];
   3.376 +		fval |= SP5[(work >>  8) & 0x3fL];
   3.377 +		fval |= SP3[(work >> 16) & 0x3fL];
   3.378 +		fval |= SP1[(work >> 24) & 0x3fL];
   3.379 +		work  = leftt ^ *keys++;
   3.380 +		fval |= SP8[ work		 & 0x3fL];
   3.381 +		fval |= SP6[(work >>  8) & 0x3fL];
   3.382 +		fval |= SP4[(work >> 16) & 0x3fL];
   3.383 +		fval |= SP2[(work >> 24) & 0x3fL];
   3.384 +		right ^= fval;
   3.385 +		}
   3.386 +
   3.387 +	right = (right << 31) | (right >> 1);
   3.388 +	work = (leftt ^ right) & 0xaaaaaaaaL;
   3.389 +	leftt ^= work;
   3.390 +	right ^= work;
   3.391 +	leftt = (leftt << 31) | (leftt >> 1);
   3.392 +	work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
   3.393 +	right ^= work;
   3.394 +	leftt ^= (work << 8);
   3.395 +	work = ((leftt >> 2) ^ right) & 0x33333333L;
   3.396 +	right ^= work;
   3.397 +	leftt ^= (work << 2);
   3.398 +	work = ((right >> 16) ^ leftt) & 0x0000ffffL;
   3.399 +	leftt ^= work;
   3.400 +	right ^= (work << 16);
   3.401 +	work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
   3.402 +	leftt ^= work;
   3.403 +	right ^= (work << 4);
   3.404 +	*block++ = right;
   3.405 +	*block = leftt;
   3.406 +	return;
   3.407 +	}
   3.408 +
   3.409 +/* Validation sets:
   3.410 + *
   3.411 + * Single-length key, single-length plaintext -
   3.412 + * Key	  : 0123 4567 89ab cdef
   3.413 + * Plain  : 0123 4567 89ab cde7
   3.414 + * Cipher : c957 4425 6a5e d31d
   3.415 + *
   3.416 + * Double-length key, single-length plaintext -
   3.417 + * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210
   3.418 + * Plain  : 0123 4567 89ab cde7
   3.419 + * Cipher : 7f1d 0a77 826b 8aff
   3.420 + *
   3.421 + * Double-length key, double-length plaintext -
   3.422 + * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210
   3.423 + * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
   3.424 + * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
   3.425 + *
   3.426 + * Triple-length key, single-length plaintext -
   3.427 + * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
   3.428 + * Plain  : 0123 4567 89ab cde7
   3.429 + * Cipher : de0b 7c06 ae5e 0ed5
   3.430 + *
   3.431 + * Triple-length key, double-length plaintext -
   3.432 + * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
   3.433 + * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
   3.434 + * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
   3.435 + *
   3.436 + * d3des V5.0a rwo 9208.07 18:44 Graven Imagery
   3.437 + **********************************************************************/
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tools/ioemu/d3des.h	Tue Oct 30 09:30:49 2007 +0000
     4.3 @@ -0,0 +1,51 @@
     4.4 +/*
     4.5 + * This is D3DES (V5.09) by Richard Outerbridge with the double and
     4.6 + * triple-length support removed for use in VNC.
     4.7 + *
     4.8 + * These changes are:
     4.9 + *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
    4.10 + *
    4.11 + * This software is distributed in the hope that it will be useful,
    4.12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    4.14 + */
    4.15 +
    4.16 +/* d3des.h -
    4.17 + *
    4.18 + *	Headers and defines for d3des.c
    4.19 + *	Graven Imagery, 1992.
    4.20 + *
    4.21 + * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
    4.22 + *	(GEnie : OUTER; CIS : [71755,204])
    4.23 + */
    4.24 +
    4.25 +#define EN0	0	/* MODE == encrypt */
    4.26 +#define DE1	1	/* MODE == decrypt */
    4.27 +
    4.28 +extern void deskey(unsigned char *, int);
    4.29 +/*		      hexkey[8]     MODE
    4.30 + * Sets the internal key register according to the hexadecimal
    4.31 + * key contained in the 8 bytes of hexkey, according to the DES,
    4.32 + * for encryption or decryption according to MODE.
    4.33 + */
    4.34 +
    4.35 +extern void usekey(unsigned long *);
    4.36 +/*		    cookedkey[32]
    4.37 + * Loads the internal key register with the data in cookedkey.
    4.38 + */
    4.39 +
    4.40 +extern void cpkey(unsigned long *);
    4.41 +/*		   cookedkey[32]
    4.42 + * Copies the contents of the internal key register into the storage
    4.43 + * located at &cookedkey[0].
    4.44 + */
    4.45 +
    4.46 +extern void des(unsigned char *, unsigned char *);
    4.47 +/*		    from[8]	      to[8]
    4.48 + * Encrypts/Decrypts (according to the key currently loaded in the
    4.49 + * internal key register) one block of eight bytes at address 'from'
    4.50 + * into the block at address 'to'.  They can be the same.
    4.51 + */
    4.52 +
    4.53 +/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
    4.54 + ********************************************************************/
     5.1 --- a/tools/ioemu/monitor.c	Tue Oct 30 09:24:17 2007 +0000
     5.2 +++ b/tools/ioemu/monitor.c	Tue Oct 30 09:30:49 2007 +0000
     5.3 @@ -374,7 +374,7 @@ void do_eject(int force, const char *fil
     5.4      eject_device(bs, force);
     5.5  }
     5.6  
     5.7 -void do_change(const char *device, const char *filename)
     5.8 +static void do_change_block(const char *device, const char *filename)
     5.9  {
    5.10      BlockDriverState *bs;
    5.11      int i;
    5.12 @@ -399,6 +399,30 @@ void do_change(const char *device, const
    5.13      }
    5.14  }
    5.15  
    5.16 +static void do_change_vnc(const char *target)
    5.17 +{
    5.18 +    if (strcmp(target, "passwd") == 0 ||
    5.19 +	strcmp(target, "password") == 0) {
    5.20 +	char password[9];
    5.21 +	monitor_readline("Password: ", 1, password, sizeof(password)-1);
    5.22 +	password[sizeof(password)-1] = '\0';
    5.23 +	if (vnc_display_password(NULL, password) < 0)
    5.24 +	    term_printf("could not set VNC server password\n");
    5.25 +    } else {
    5.26 +	if (vnc_display_open(NULL, target, 0) < 0)
    5.27 +	    term_printf("could not start VNC server on %s\n", target);
    5.28 +    }
    5.29 +}
    5.30 +
    5.31 +void do_change(const char *device, const char *target)
    5.32 +{
    5.33 +    if (strcmp(device, "vnc") == 0) {
    5.34 +	do_change_vnc(target);
    5.35 +    } else {
    5.36 +	do_change_block(device, target);
    5.37 +    }
    5.38 +}
    5.39 +
    5.40  static void do_screen_dump(const char *filename)
    5.41  {
    5.42      vga_hw_screen_dump(filename);
     6.1 --- a/tools/ioemu/vl.c	Tue Oct 30 09:24:17 2007 +0000
     6.2 +++ b/tools/ioemu/vl.c	Tue Oct 30 09:30:49 2007 +0000
     6.3 @@ -7683,8 +7683,14 @@ int main(int argc, char **argv)
     6.4          dumb_display_init(ds);
     6.5      } else if (vnc_display != NULL || vncunused != 0) {
     6.6  	int vnc_display_port;
     6.7 -	vnc_display_port = vnc_display_init(ds, vnc_display, vncunused);
     6.8 -	if (vncviewer)
     6.9 +	char password[20];
    6.10 +	vnc_display_init(ds);
    6.11 +	if (xenstore_read_vncpasswd(domid, password, sizeof(password)) < 0)
    6.12 +	    exit(0);
    6.13 +	vnc_display_password(ds, password);
    6.14 +	if ((vnc_display_port = vnc_display_open(ds, vnc_display, vncunused)) < 0) 
    6.15 +	    exit (0);
    6.16 + 	if (vncviewer)
    6.17  	    vnc_start_viewer(vnc_display_port);
    6.18  	xenstore_write_vncport(vnc_display_port);
    6.19      } else {
     7.1 --- a/tools/ioemu/vl.h	Tue Oct 30 09:24:17 2007 +0000
     7.2 +++ b/tools/ioemu/vl.h	Tue Oct 30 09:30:49 2007 +0000
     7.3 @@ -943,7 +943,10 @@ void sdl_display_init(DisplayState *ds, 
     7.4  void cocoa_display_init(DisplayState *ds, int full_screen);
     7.5  
     7.6  /* vnc.c */
     7.7 -int vnc_display_init(DisplayState *ds, const char *display, int find_unused);
     7.8 +void vnc_display_init(DisplayState *ds);
     7.9 +void vnc_display_close(DisplayState *ds);
    7.10 +int vnc_display_open(DisplayState *ds, const char * display, int find_unused);
    7.11 +int vnc_display_password(DisplayState *ds, const char *password);
    7.12  void do_info_vnc(void);
    7.13  int vnc_start_viewer(int port);
    7.14  
     8.1 --- a/tools/ioemu/vnc.c	Tue Oct 30 09:24:17 2007 +0000
     8.2 +++ b/tools/ioemu/vnc.c	Tue Oct 30 09:30:49 2007 +0000
     8.3 @@ -47,6 +47,28 @@
     8.4  
     8.5  #include "vnc_keysym.h"
     8.6  #include "keymaps.c"
     8.7 +#include "d3des.h"
     8.8 +
     8.9 +#if CONFIG_VNC_TLS
    8.10 +#include <gnutls/gnutls.h>
    8.11 +#include <gnutls/x509.h>
    8.12 +#endif /* CONFIG_VNC_TLS */
    8.13 +
    8.14 +// #define _VNC_DEBUG 1
    8.15 +
    8.16 +#if _VNC_DEBUG
    8.17 +#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
    8.18 +
    8.19 +#if CONFIG_VNC_TLS && _VNC_DEBUG >= 2
    8.20 +/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
    8.21 +static void vnc_debug_gnutls_log(int level, const char* str) {
    8.22 +    VNC_DEBUG("%d %s", level, str);
    8.23 +}
    8.24 +#endif /* CONFIG_VNC_TLS && _VNC_DEBUG */
    8.25 +#else
    8.26 +#define VNC_DEBUG(fmt, ...) do { } while (0)
    8.27 +#endif
    8.28 +
    8.29  
    8.30  typedef struct Buffer
    8.31  {
    8.32 @@ -73,6 +95,45 @@ typedef void VncSendHextileTile(VncState
    8.33  #define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32))
    8.34  #endif
    8.35  
    8.36 +#define VNC_AUTH_CHALLENGE_SIZE 16
    8.37 +
    8.38 +enum {
    8.39 +    VNC_AUTH_INVALID = 0,
    8.40 +    VNC_AUTH_NONE = 1,
    8.41 +    VNC_AUTH_VNC = 2,
    8.42 +    VNC_AUTH_RA2 = 5,
    8.43 +    VNC_AUTH_RA2NE = 6,
    8.44 +    VNC_AUTH_TIGHT = 16,
    8.45 +    VNC_AUTH_ULTRA = 17,
    8.46 +    VNC_AUTH_TLS = 18,
    8.47 +    VNC_AUTH_VENCRYPT = 19
    8.48 +};
    8.49 +
    8.50 +#if CONFIG_VNC_TLS
    8.51 +enum {
    8.52 +    VNC_WIREMODE_CLEAR,
    8.53 +    VNC_WIREMODE_TLS,
    8.54 +};
    8.55 +
    8.56 +enum {
    8.57 +    VNC_AUTH_VENCRYPT_PLAIN = 256,
    8.58 +    VNC_AUTH_VENCRYPT_TLSNONE = 257,
    8.59 +    VNC_AUTH_VENCRYPT_TLSVNC = 258,
    8.60 +    VNC_AUTH_VENCRYPT_TLSPLAIN = 259,
    8.61 +    VNC_AUTH_VENCRYPT_X509NONE = 260,
    8.62 +    VNC_AUTH_VENCRYPT_X509VNC = 261,
    8.63 +    VNC_AUTH_VENCRYPT_X509PLAIN = 262,
    8.64 +};
    8.65 +
    8.66 +#if CONFIG_VNC_TLS
    8.67 +#define X509_CA_CERT_FILE "ca-cert.pem"
    8.68 +#define X509_CA_CRL_FILE "ca-crl.pem"
    8.69 +#define X509_SERVER_KEY_FILE "server-key.pem"
    8.70 +#define X509_SERVER_CERT_FILE "server-cert.pem"
    8.71 +#endif
    8.72 +
    8.73 +#endif /* CONFIG_VNC_TLS */
    8.74 +
    8.75  struct VncState
    8.76  {
    8.77      QEMUTimer *timer;
    8.78 @@ -97,7 +158,27 @@ struct VncState
    8.79      int last_x;
    8.80      int last_y;
    8.81  
    8.82 -    const char *display;
    8.83 +    int major;
    8.84 +    int minor;
    8.85 +
    8.86 +    char *display;
    8.87 +    char *password;
    8.88 +    int auth;
    8.89 +#if CONFIG_VNC_TLS
    8.90 +    int subauth;
    8.91 +    int x509verify;
    8.92 +
    8.93 +    char *x509cacert;
    8.94 +    char *x509cacrl;
    8.95 +    char *x509cert;
    8.96 +    char *x509key;
    8.97 +#endif
    8.98 +    char challenge[VNC_AUTH_CHALLENGE_SIZE];
    8.99 +
   8.100 +#if CONFIG_VNC_TLS
   8.101 +    int wiremode;
   8.102 +    gnutls_session_t tls_session;
   8.103 +#endif
   8.104  
   8.105      Buffer output;
   8.106      Buffer input;
   8.107 @@ -698,11 +779,19 @@ static int vnc_client_io_error(VncState 
   8.108  	if (ret == -1 && (last_errno == EINTR || last_errno == EAGAIN))
   8.109  	    return 0;
   8.110  
   8.111 +	VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0);
   8.112  	qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
   8.113  	closesocket(vs->csock);
   8.114  	vs->csock = -1;
   8.115  	buffer_reset(&vs->input);
   8.116  	buffer_reset(&vs->output);
   8.117 +#if CONFIG_VNC_TLS
   8.118 +	if (vs->tls_session) {
   8.119 +	    gnutls_deinit(vs->tls_session);
   8.120 +	    vs->tls_session = NULL;
   8.121 +	}
   8.122 +	vs->wiremode = VNC_WIREMODE_CLEAR;
   8.123 +#endif /* CONFIG_VNC_TLS */
   8.124  	return 0;
   8.125      }
   8.126      return ret;
   8.127 @@ -718,7 +807,19 @@ static void vnc_client_write(void *opaqu
   8.128      long ret;
   8.129      VncState *vs = opaque;
   8.130  
   8.131 -    ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0);
   8.132 +#if CONFIG_VNC_TLS
   8.133 +    if (vs->tls_session) {
   8.134 +	ret = gnutls_write(vs->tls_session, vs->output.buffer, vs->output.offset);
   8.135 +	if (ret < 0) {
   8.136 +	    if (ret == GNUTLS_E_AGAIN)
   8.137 +		errno = EAGAIN;
   8.138 +	    else
   8.139 +		errno = EIO;
   8.140 +	    ret = -1;
   8.141 +	}
   8.142 +    } else
   8.143 +#endif /* CONFIG_VNC_TLS */
   8.144 +	ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0);
   8.145      ret = vnc_client_io_error(vs, ret, socket_error());
   8.146      if (!ret)
   8.147  	return;
   8.148 @@ -744,7 +845,19 @@ static void vnc_client_read(void *opaque
   8.149  
   8.150      buffer_reserve(&vs->input, 4096);
   8.151  
   8.152 -    ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0);
   8.153 +#if CONFIG_VNC_TLS
   8.154 +    if (vs->tls_session) {
   8.155 +	ret = gnutls_read(vs->tls_session, buffer_end(&vs->input), 4096);
   8.156 +	if (ret < 0) {
   8.157 +	    if (ret == GNUTLS_E_AGAIN)
   8.158 +		errno = EAGAIN;
   8.159 +	    else
   8.160 +		errno = EIO;
   8.161 +	    ret = -1;
   8.162 +	}
   8.163 +    } else
   8.164 +#endif /* CONFIG_VNC_TLS */
   8.165 +	ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0);
   8.166      ret = vnc_client_io_error(vs, ret, socket_error());
   8.167      if (!ret)
   8.168  	return;
   8.169 @@ -841,6 +954,41 @@ static uint32_t read_u32(uint8_t *data, 
   8.170  	    (data[offset + 2] << 8) | data[offset + 3]);
   8.171  }
   8.172  
   8.173 +#if CONFIG_VNC_TLS
   8.174 +ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
   8.175 +		     const void *data,
   8.176 +		     size_t len) {
   8.177 +    struct VncState *vs = (struct VncState *)transport;
   8.178 +    int ret;
   8.179 +
   8.180 + retry:
   8.181 +    ret = send(vs->csock, data, len, 0);
   8.182 +    if (ret < 0) {
   8.183 +	if (errno == EINTR)
   8.184 +	    goto retry;
   8.185 +	return -1;
   8.186 +    }
   8.187 +    return ret;
   8.188 +}
   8.189 +
   8.190 +
   8.191 +ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
   8.192 +		     void *data,
   8.193 +		     size_t len) {
   8.194 +    struct VncState *vs = (struct VncState *)transport;
   8.195 +    int ret;
   8.196 +
   8.197 + retry:
   8.198 +    ret = recv(vs->csock, data, len, 0);
   8.199 +    if (ret < 0) {
   8.200 +	if (errno == EINTR)
   8.201 +	    goto retry;
   8.202 +	return -1;
   8.203 +    }
   8.204 +    return ret;
   8.205 +}
   8.206 +#endif /* CONFIG_VNC_TLS */
   8.207 +
   8.208  static void client_cut_text(VncState *vs, size_t len, char *text)
   8.209  {
   8.210  }
   8.211 @@ -1384,23 +1532,591 @@ static int protocol_client_init(VncState
   8.212  }
   8.213  
   8.214  
   8.215 -static int protocol_version(VncState *vs, uint8_t *version, size_t len)
   8.216 +static void make_challenge(VncState *vs)
   8.217 +{
   8.218 +    int i;
   8.219 +
   8.220 +    srand(time(NULL)+getpid()+getpid()*987654+rand());
   8.221 +
   8.222 +    for (i = 0 ; i < sizeof(vs->challenge) ; i++)
   8.223 +        vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
   8.224 +}
   8.225 +
   8.226 +static int protocol_client_auth_vnc(VncState *vs, char *data, size_t len)
   8.227 +{
   8.228 +    char response[VNC_AUTH_CHALLENGE_SIZE];
   8.229 +    int i, j, pwlen;
   8.230 +    char key[8];
   8.231 +
   8.232 +    if (!vs->password || !vs->password[0]) {
   8.233 +	VNC_DEBUG("No password configured on server");
   8.234 +	vnc_write_u32(vs, 1); /* Reject auth */
   8.235 +	if (vs->minor >= 8) {
   8.236 +	    static const char err[] = "Authentication failed";
   8.237 +	    vnc_write_u32(vs, sizeof(err));
   8.238 +	    vnc_write(vs, err, sizeof(err));
   8.239 +	}
   8.240 +	vnc_flush(vs);
   8.241 +	vnc_client_error(vs);
   8.242 +	return 0;
   8.243 +    }
   8.244 +
   8.245 +    memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
   8.246 +
   8.247 +    /* Calculate the expected challenge response */
   8.248 +    pwlen = strlen(vs->password);
   8.249 +    for (i=0; i<sizeof(key); i++)
   8.250 +        key[i] = i<pwlen ? vs->password[i] : 0;
   8.251 +    deskey(key, EN0);
   8.252 +    for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
   8.253 +        des(response+j, response+j);
   8.254 +
   8.255 +    /* Compare expected vs actual challenge response */
   8.256 +    if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
   8.257 +	VNC_DEBUG("Client challenge reponse did not match\n");
   8.258 +	vnc_write_u32(vs, 1); /* Reject auth */
   8.259 +	if (vs->minor >= 8) {
   8.260 +	    static const char err[] = "Authentication failed";
   8.261 +	    vnc_write_u32(vs, sizeof(err));
   8.262 +	    vnc_write(vs, err, sizeof(err));
   8.263 +	}
   8.264 +	vnc_flush(vs);
   8.265 +	vnc_client_error(vs);
   8.266 +    } else {
   8.267 +	VNC_DEBUG("Accepting VNC challenge response\n");
   8.268 +	vnc_write_u32(vs, 0); /* Accept auth */
   8.269 +	vnc_flush(vs);
   8.270 +
   8.271 +	vnc_read_when(vs, protocol_client_init, 1);
   8.272 +    }
   8.273 +    return 0;
   8.274 +}
   8.275 +
   8.276 +static int start_auth_vnc(VncState *vs)
   8.277 +{
   8.278 +    make_challenge(vs);
   8.279 +    /* Send client a 'random' challenge */
   8.280 +    vnc_write(vs, vs->challenge, sizeof(vs->challenge));
   8.281 +    vnc_flush(vs);
   8.282 +
   8.283 +    vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
   8.284 +    return 0;
   8.285 +}
   8.286 +
   8.287 +
   8.288 +#if CONFIG_VNC_TLS
   8.289 +#define DH_BITS 1024
   8.290 +static gnutls_dh_params_t dh_params;
   8.291 +
   8.292 +static int vnc_tls_initialize(void)
   8.293 +{
   8.294 +    static int tlsinitialized = 0;
   8.295 +
   8.296 +    if (tlsinitialized)
   8.297 +	return 1;
   8.298 +
   8.299 +    if (gnutls_global_init () < 0)
   8.300 +	return 0;
   8.301 +
   8.302 +    /* XXX ought to re-generate diffie-hellmen params periodically */
   8.303 +    if (gnutls_dh_params_init (&dh_params) < 0)
   8.304 +	return 0;
   8.305 +    if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
   8.306 +	return 0;
   8.307 +
   8.308 +#if _VNC_DEBUG == 2
   8.309 +    gnutls_global_set_log_level(10);
   8.310 +    gnutls_global_set_log_function(vnc_debug_gnutls_log);
   8.311 +#endif
   8.312 +
   8.313 +    tlsinitialized = 1;
   8.314 +
   8.315 +    return 1;
   8.316 +}
   8.317 +
   8.318 +static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
   8.319 +{
   8.320 +    gnutls_anon_server_credentials anon_cred;
   8.321 +    int ret;
   8.322 +
   8.323 +    if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
   8.324 +	VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
   8.325 +	return NULL;
   8.326 +    }
   8.327 +
   8.328 +    gnutls_anon_set_server_dh_params(anon_cred, dh_params);
   8.329 +
   8.330 +    return anon_cred;
   8.331 +}
   8.332 +
   8.333 +
   8.334 +static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *vs)
   8.335 +{
   8.336 +    gnutls_certificate_credentials_t x509_cred;
   8.337 +    int ret;
   8.338 +
   8.339 +    if (!vs->x509cacert) {
   8.340 +	VNC_DEBUG("No CA x509 certificate specified\n");
   8.341 +	return NULL;
   8.342 +    }
   8.343 +    if (!vs->x509cert) {
   8.344 +	VNC_DEBUG("No server x509 certificate specified\n");
   8.345 +	return NULL;
   8.346 +    }
   8.347 +    if (!vs->x509key) {
   8.348 +	VNC_DEBUG("No server private key specified\n");
   8.349 +	return NULL;
   8.350 +    }
   8.351 +
   8.352 +    if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
   8.353 +	VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
   8.354 +	return NULL;
   8.355 +    }
   8.356 +    if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
   8.357 +						      vs->x509cacert,
   8.358 +						      GNUTLS_X509_FMT_PEM)) < 0) {
   8.359 +	VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
   8.360 +	gnutls_certificate_free_credentials(x509_cred);
   8.361 +	return NULL;
   8.362 +    }
   8.363 +
   8.364 +    if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
   8.365 +						     vs->x509cert,
   8.366 +						     vs->x509key,
   8.367 +						     GNUTLS_X509_FMT_PEM)) < 0) {
   8.368 +	VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
   8.369 +	gnutls_certificate_free_credentials(x509_cred);
   8.370 +	return NULL;
   8.371 +    }
   8.372 +
   8.373 +    if (vs->x509cacrl) {
   8.374 +	if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
   8.375 +							vs->x509cacrl,
   8.376 +							GNUTLS_X509_FMT_PEM)) < 0) {
   8.377 +	    VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
   8.378 +	    gnutls_certificate_free_credentials(x509_cred);
   8.379 +	    return NULL;
   8.380 +	}
   8.381 +    }
   8.382 +
   8.383 +    gnutls_certificate_set_dh_params (x509_cred, dh_params);
   8.384 +
   8.385 +    return x509_cred;
   8.386 +}
   8.387 +
   8.388 +static int vnc_validate_certificate(struct VncState *vs)
   8.389 +{
   8.390 +    int ret;
   8.391 +    unsigned int status;
   8.392 +    const gnutls_datum_t *certs;
   8.393 +    unsigned int nCerts, i;
   8.394 +    time_t now;
   8.395 +
   8.396 +    VNC_DEBUG("Validating client certificate\n");
   8.397 +    if ((ret = gnutls_certificate_verify_peers2 (vs->tls_session, &status)) < 0) {
   8.398 +	VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
   8.399 +	return -1;
   8.400 +    }
   8.401 +
   8.402 +    if ((now = time(NULL)) == ((time_t)-1)) {
   8.403 +	return -1;
   8.404 +    }
   8.405 +
   8.406 +    if (status != 0) {
   8.407 +	if (status & GNUTLS_CERT_INVALID)
   8.408 +	    VNC_DEBUG("The certificate is not trusted.\n");
   8.409 +
   8.410 +	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
   8.411 +	    VNC_DEBUG("The certificate hasn't got a known issuer.\n");
   8.412 +
   8.413 +	if (status & GNUTLS_CERT_REVOKED)
   8.414 +	    VNC_DEBUG("The certificate has been revoked.\n");
   8.415 +
   8.416 +	if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
   8.417 +	    VNC_DEBUG("The certificate uses an insecure algorithm\n");
   8.418 +
   8.419 +	return -1;
   8.420 +    } else {
   8.421 +	VNC_DEBUG("Certificate is valid!\n");
   8.422 +    }
   8.423 +
   8.424 +    /* Only support x509 for now */
   8.425 +    if (gnutls_certificate_type_get(vs->tls_session) != GNUTLS_CRT_X509)
   8.426 +	return -1;
   8.427 +
   8.428 +    if (!(certs = gnutls_certificate_get_peers(vs->tls_session, &nCerts)))
   8.429 +	return -1;
   8.430 +
   8.431 +    for (i = 0 ; i < nCerts ; i++) {
   8.432 +	gnutls_x509_crt_t cert;
   8.433 +	VNC_DEBUG ("Checking certificate chain %d\n", i);
   8.434 +	if (gnutls_x509_crt_init (&cert) < 0)
   8.435 +	    return -1;
   8.436 +
   8.437 +	if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
   8.438 +	    gnutls_x509_crt_deinit (cert);
   8.439 +	    return -1;
   8.440 +	}
   8.441 +
   8.442 +	if (gnutls_x509_crt_get_expiration_time (cert) < now) {
   8.443 +	    VNC_DEBUG("The certificate has expired\n");
   8.444 +	    gnutls_x509_crt_deinit (cert);
   8.445 +	    return -1;
   8.446 +	}
   8.447 +
   8.448 +	if (gnutls_x509_crt_get_activation_time (cert) > now) {
   8.449 +	    VNC_DEBUG("The certificate is not yet activated\n");
   8.450 +	    gnutls_x509_crt_deinit (cert);
   8.451 +	    return -1;
   8.452 +	}
   8.453 +
   8.454 +	if (gnutls_x509_crt_get_activation_time (cert) > now) {
   8.455 +	    VNC_DEBUG("The certificate is not yet activated\n");
   8.456 +	    gnutls_x509_crt_deinit (cert);
   8.457 +	    return -1;
   8.458 +	}
   8.459 +
   8.460 +	gnutls_x509_crt_deinit (cert);
   8.461 +    }
   8.462 +
   8.463 +    return 0;
   8.464 +}
   8.465 +
   8.466 +
   8.467 +static int start_auth_vencrypt_subauth(VncState *vs)
   8.468 +{
   8.469 +    switch (vs->subauth) {
   8.470 +    case VNC_AUTH_VENCRYPT_TLSNONE:
   8.471 +    case VNC_AUTH_VENCRYPT_X509NONE:
   8.472 +       VNC_DEBUG("Accept TLS auth none\n");
   8.473 +       vnc_write_u32(vs, 0); /* Accept auth completion */
   8.474 +       vnc_read_when(vs, protocol_client_init, 1);
   8.475 +       break;
   8.476 +
   8.477 +    case VNC_AUTH_VENCRYPT_TLSVNC:
   8.478 +    case VNC_AUTH_VENCRYPT_X509VNC:
   8.479 +       VNC_DEBUG("Start TLS auth VNC\n");
   8.480 +       return start_auth_vnc(vs);
   8.481 +
   8.482 +    default: /* Should not be possible, but just in case */
   8.483 +       VNC_DEBUG("Reject auth %d\n", vs->auth);
   8.484 +       vnc_write_u8(vs, 1);
   8.485 +       if (vs->minor >= 8) {
   8.486 +           static const char err[] = "Unsupported authentication type";
   8.487 +           vnc_write_u32(vs, sizeof(err));
   8.488 +           vnc_write(vs, err, sizeof(err));
   8.489 +       }
   8.490 +       vnc_client_error(vs);
   8.491 +    }
   8.492 +
   8.493 +    return 0;
   8.494 +}
   8.495 +
   8.496 +static void vnc_handshake_io(void *opaque);
   8.497 +
   8.498 +static int vnc_continue_handshake(struct VncState *vs) {
   8.499 +    int ret;
   8.500 +
   8.501 +    if ((ret = gnutls_handshake(vs->tls_session)) < 0) {
   8.502 +       if (!gnutls_error_is_fatal(ret)) {
   8.503 +           VNC_DEBUG("Handshake interrupted (blocking)\n");
   8.504 +           if (!gnutls_record_get_direction(vs->tls_session))
   8.505 +               qemu_set_fd_handler(vs->csock, vnc_handshake_io, NULL, vs);
   8.506 +           else
   8.507 +               qemu_set_fd_handler(vs->csock, NULL, vnc_handshake_io, vs);
   8.508 +           return 0;
   8.509 +       }
   8.510 +       VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
   8.511 +       vnc_client_error(vs);
   8.512 +       return -1;
   8.513 +    }
   8.514 +
   8.515 +    if (vs->x509verify) {
   8.516 +	if (vnc_validate_certificate(vs) < 0) {
   8.517 +	    VNC_DEBUG("Client verification failed\n");
   8.518 +	    vnc_client_error(vs);
   8.519 +	    return -1;
   8.520 +	} else {
   8.521 +	    VNC_DEBUG("Client verification passed\n");
   8.522 +	}
   8.523 +    }
   8.524 +
   8.525 +    VNC_DEBUG("Handshake done, switching to TLS data mode\n");
   8.526 +    vs->wiremode = VNC_WIREMODE_TLS;
   8.527 +    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
   8.528 +
   8.529 +    return start_auth_vencrypt_subauth(vs);
   8.530 +}
   8.531 +
   8.532 +static void vnc_handshake_io(void *opaque) {
   8.533 +    struct VncState *vs = (struct VncState *)opaque;
   8.534 +
   8.535 +    VNC_DEBUG("Handshake IO continue\n");
   8.536 +    vnc_continue_handshake(vs);
   8.537 +}
   8.538 +
   8.539 +#define NEED_X509_AUTH(vs)			      \
   8.540 +    ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
   8.541 +     (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
   8.542 +     (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
   8.543 +
   8.544 +
   8.545 +static int vnc_start_tls(struct VncState *vs) {
   8.546 +    static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
   8.547 +    static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
   8.548 +    static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
   8.549 +    static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
   8.550 +
   8.551 +    VNC_DEBUG("Do TLS setup\n");
   8.552 +    if (vnc_tls_initialize() < 0) {
   8.553 +	VNC_DEBUG("Failed to init TLS\n");
   8.554 +	vnc_client_error(vs);
   8.555 +	return -1;
   8.556 +    }
   8.557 +    if (vs->tls_session == NULL) {
   8.558 +	if (gnutls_init(&vs->tls_session, GNUTLS_SERVER) < 0) {
   8.559 +	    vnc_client_error(vs);
   8.560 +	    return -1;
   8.561 +	}
   8.562 +
   8.563 +	if (gnutls_set_default_priority(vs->tls_session) < 0) {
   8.564 +	    gnutls_deinit(vs->tls_session);
   8.565 +	    vs->tls_session = NULL;
   8.566 +	    vnc_client_error(vs);
   8.567 +	    return -1;
   8.568 +	}
   8.569 +
   8.570 +	if (gnutls_kx_set_priority(vs->tls_session, NEED_X509_AUTH(vs) ? kx_x509 : kx_anon) < 0) {
   8.571 +	    gnutls_deinit(vs->tls_session);
   8.572 +	    vs->tls_session = NULL;
   8.573 +	    vnc_client_error(vs);
   8.574 +	    return -1;
   8.575 +	}
   8.576 +
   8.577 +	if (gnutls_certificate_type_set_priority(vs->tls_session, cert_type_priority) < 0) {
   8.578 +	    gnutls_deinit(vs->tls_session);
   8.579 +	    vs->tls_session = NULL;
   8.580 +	    vnc_client_error(vs);
   8.581 +	    return -1;
   8.582 +	}
   8.583 +
   8.584 +	if (gnutls_protocol_set_priority(vs->tls_session, protocol_priority) < 0) {
   8.585 +	    gnutls_deinit(vs->tls_session);
   8.586 +	    vs->tls_session = NULL;
   8.587 +	    vnc_client_error(vs);
   8.588 +	    return -1;
   8.589 +	}
   8.590 +
   8.591 +	if (NEED_X509_AUTH(vs)) {
   8.592 +	    gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs);
   8.593 +	    if (!x509_cred) {
   8.594 +		gnutls_deinit(vs->tls_session);
   8.595 +		vs->tls_session = NULL;
   8.596 +		vnc_client_error(vs);
   8.597 +		return -1;
   8.598 +	    }
   8.599 +	    if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
   8.600 +		gnutls_deinit(vs->tls_session);
   8.601 +		vs->tls_session = NULL;
   8.602 +		gnutls_certificate_free_credentials(x509_cred);
   8.603 +		vnc_client_error(vs);
   8.604 +		return -1;
   8.605 +	    }
   8.606 +	    if (vs->x509verify) {
   8.607 +		VNC_DEBUG("Requesting a client certificate\n");
   8.608 +		gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST);
   8.609 +	    }
   8.610 +
   8.611 +	} else {
   8.612 +	    gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
   8.613 +	    if (!anon_cred) {
   8.614 +		gnutls_deinit(vs->tls_session);
   8.615 +		vs->tls_session = NULL;
   8.616 +		vnc_client_error(vs);
   8.617 +		return -1;
   8.618 +	    }
   8.619 +	    if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) {
   8.620 +		gnutls_deinit(vs->tls_session);
   8.621 +		vs->tls_session = NULL;
   8.622 +		gnutls_anon_free_server_credentials(anon_cred);
   8.623 +		vnc_client_error(vs);
   8.624 +		return -1;
   8.625 +	    }
   8.626 +	}
   8.627 +
   8.628 +	gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs);
   8.629 +	gnutls_transport_set_push_function(vs->tls_session, vnc_tls_push);
   8.630 +	gnutls_transport_set_pull_function(vs->tls_session, vnc_tls_pull);
   8.631 +    }
   8.632 +
   8.633 +    VNC_DEBUG("Start TLS handshake process\n");
   8.634 +    return vnc_continue_handshake(vs);
   8.635 +}
   8.636 +
   8.637 +static int protocol_client_vencrypt_auth(VncState *vs, char *data, size_t len)
   8.638 +{
   8.639 +    int auth = read_u32(data, 0);
   8.640 +
   8.641 +    if (auth != vs->subauth) {
   8.642 +	VNC_DEBUG("Rejecting auth %d\n", auth);
   8.643 +	vnc_write_u8(vs, 0); /* Reject auth */
   8.644 +	vnc_flush(vs);
   8.645 +	vnc_client_error(vs);
   8.646 +    } else {
   8.647 +	VNC_DEBUG("Accepting auth %d, starting handshake\n", auth);
   8.648 +	vnc_write_u8(vs, 1); /* Accept auth */
   8.649 +	vnc_flush(vs);
   8.650 +
   8.651 +	if (vnc_start_tls(vs) < 0) {
   8.652 +	    VNC_DEBUG("Failed to complete TLS\n");
   8.653 +	    return 0;
   8.654 +	}
   8.655 +
   8.656 +	if (vs->wiremode == VNC_WIREMODE_TLS) {
   8.657 +	    VNC_DEBUG("Starting VeNCrypt subauth\n");
   8.658 +	    return start_auth_vencrypt_subauth(vs);
   8.659 +	} else {
   8.660 +	    VNC_DEBUG("TLS handshake blocked\n");
   8.661 +	    return 0;
   8.662 +	}
   8.663 +    }
   8.664 +    return 0;
   8.665 +}
   8.666 +
   8.667 +static int protocol_client_vencrypt_init(VncState *vs, char *data, size_t len)
   8.668 +{
   8.669 +    if (data[0] != 0 ||
   8.670 +	data[1] != 2) {
   8.671 +	VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]);
   8.672 +	vnc_write_u8(vs, 1); /* Reject version */
   8.673 +	vnc_flush(vs);
   8.674 +	vnc_client_error(vs);
   8.675 +    } else {
   8.676 +	VNC_DEBUG("Sending allowed auth %d\n", vs->subauth);
   8.677 +	vnc_write_u8(vs, 0); /* Accept version */
   8.678 +	vnc_write_u8(vs, 1); /* Number of sub-auths */
   8.679 +	vnc_write_u32(vs, vs->subauth); /* The supported auth */
   8.680 +	vnc_flush(vs);
   8.681 +	vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
   8.682 +    }
   8.683 +    return 0;
   8.684 +}
   8.685 +
   8.686 +static int start_auth_vencrypt(VncState *vs)
   8.687 +{
   8.688 +    /* Send VeNCrypt version 0.2 */
   8.689 +    vnc_write_u8(vs, 0);
   8.690 +    vnc_write_u8(vs, 2);
   8.691 +
   8.692 +    vnc_read_when(vs, protocol_client_vencrypt_init, 2);
   8.693 +    return 0;
   8.694 +}
   8.695 +#endif /* CONFIG_VNC_TLS */
   8.696 +
   8.697 +static int protocol_client_auth(VncState *vs, char *data, size_t len)
   8.698 +{
   8.699 +    /* We only advertise 1 auth scheme at a time, so client
   8.700 +     * must pick the one we sent. Verify this */
   8.701 +    if (data[0] != vs->auth) { /* Reject auth */
   8.702 +       VNC_DEBUG("Reject auth %d\n", (int)data[0]);
   8.703 +       vnc_write_u32(vs, 1);
   8.704 +       if (vs->minor >= 8) {
   8.705 +           static const char err[] = "Authentication failed";
   8.706 +           vnc_write_u32(vs, sizeof(err));
   8.707 +           vnc_write(vs, err, sizeof(err));
   8.708 +       }
   8.709 +       vnc_client_error(vs);
   8.710 +    } else { /* Accept requested auth */
   8.711 +       VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
   8.712 +       switch (vs->auth) {
   8.713 +       case VNC_AUTH_NONE:
   8.714 +           VNC_DEBUG("Accept auth none\n");
   8.715 +           if (vs->minor >= 8) {
   8.716 +               vnc_write_u32(vs, 0); /* Accept auth completion */
   8.717 +               vnc_flush(vs);
   8.718 +           }
   8.719 +           vnc_read_when(vs, protocol_client_init, 1);
   8.720 +           break;
   8.721 +
   8.722 +       case VNC_AUTH_VNC:
   8.723 +           VNC_DEBUG("Start VNC auth\n");
   8.724 +           return start_auth_vnc(vs);
   8.725 +
   8.726 +#if CONFIG_VNC_TLS
   8.727 +       case VNC_AUTH_VENCRYPT:
   8.728 +           VNC_DEBUG("Accept VeNCrypt auth\n");;
   8.729 +           return start_auth_vencrypt(vs);
   8.730 +#endif /* CONFIG_VNC_TLS */
   8.731 +
   8.732 +       default: /* Should not be possible, but just in case */
   8.733 +           VNC_DEBUG("Reject auth %d\n", vs->auth);
   8.734 +           vnc_write_u8(vs, 1);
   8.735 +           if (vs->minor >= 8) {
   8.736 +               static const char err[] = "Authentication failed";
   8.737 +               vnc_write_u32(vs, sizeof(err));
   8.738 +               vnc_write(vs, err, sizeof(err));
   8.739 +           }
   8.740 +           vnc_client_error(vs);
   8.741 +       }
   8.742 +    }
   8.743 +    return 0;
   8.744 +}
   8.745 +
   8.746 +static int protocol_version(VncState *vs, char *version, size_t len)
   8.747  {
   8.748      char local[13];
   8.749 -    int maj, min;
   8.750  
   8.751      memcpy(local, version, 12);
   8.752      local[12] = 0;
   8.753  
   8.754 -    if (sscanf(local, "RFB %03d.%03d\n", &maj, &min) != 2) {
   8.755 +    if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
   8.756 +	VNC_DEBUG("Malformed protocol version %s\n", local);
   8.757  	vnc_client_error(vs);
   8.758  	return 0;
   8.759      }
   8.760 +    VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
   8.761 +    if (vs->major != 3 ||
   8.762 +	(vs->minor != 3 &&
   8.763 +	 vs->minor != 4 &&
   8.764 +	 vs->minor != 5 &&
   8.765 +	 vs->minor != 7 &&
   8.766 +	 vs->minor != 8)) {
   8.767 +	VNC_DEBUG("Unsupported client version\n");
   8.768 +	vnc_write_u32(vs, VNC_AUTH_INVALID);
   8.769 +	vnc_flush(vs);
   8.770 +	vnc_client_error(vs);
   8.771 +	return 0;
   8.772 +    }
   8.773 +    /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
   8.774 +     * as equivalent to v3.3 by servers
   8.775 +     */
   8.776 +    if (vs->minor == 4 || vs->minor == 5)
   8.777 +	vs->minor = 3;
   8.778  
   8.779 -    vnc_write_u32(vs, 1); /* None */
   8.780 -    vnc_flush(vs);
   8.781 -  
   8.782 -    vnc_read_when(vs, protocol_client_init, 1);
   8.783 +    if (vs->minor == 3) {
   8.784 +	if (vs->auth == VNC_AUTH_NONE) {
   8.785 +            VNC_DEBUG("Tell client auth none\n");
   8.786 +            vnc_write_u32(vs, vs->auth);
   8.787 +            vnc_flush(vs);
   8.788 +            vnc_read_when(vs, protocol_client_init, 1);
   8.789 +       } else if (vs->auth == VNC_AUTH_VNC) {
   8.790 +            VNC_DEBUG("Tell client VNC auth\n");
   8.791 +            vnc_write_u32(vs, vs->auth);
   8.792 +            vnc_flush(vs);
   8.793 +            start_auth_vnc(vs);
   8.794 +       } else {
   8.795 +            VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth);
   8.796 +            vnc_write_u32(vs, VNC_AUTH_INVALID);
   8.797 +            vnc_flush(vs);
   8.798 +            vnc_client_error(vs);
   8.799 +       }
   8.800 +    } else {
   8.801 +	VNC_DEBUG("Telling client we support auth %d\n", vs->auth);
   8.802 +	vnc_write_u8(vs, 1); /* num auth */
   8.803 +	vnc_write_u8(vs, vs->auth);
   8.804 +	vnc_read_when(vs, protocol_client_auth, 1);
   8.805 +	vnc_flush(vs);
   8.806 +    }
   8.807  
   8.808      return 0;
   8.809  }
   8.810 @@ -1413,9 +2129,10 @@ static void vnc_listen_read(void *opaque
   8.811  
   8.812      vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
   8.813      if (vs->csock != -1) {
   8.814 +	VNC_DEBUG("New client on socket %d\n", vs->csock);
   8.815          socket_set_nonblock(vs->csock);
   8.816  	qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque);
   8.817 -	vnc_write(vs, "RFB 003.003\n", 12);
   8.818 +	vnc_write(vs, "RFB 003.008\n", 12);
   8.819  	vnc_flush(vs);
   8.820  	vnc_read_when(vs, protocol_version, 12);
   8.821  	framebuffer_set_updated(vs, 0, 0, vs->ds->width, vs->ds->height);
   8.822 @@ -1428,16 +2145,8 @@ static void vnc_listen_read(void *opaque
   8.823  
   8.824  extern int parse_host_port(struct sockaddr_in *saddr, const char *str);
   8.825  
   8.826 -int vnc_display_init(DisplayState *ds, const char *arg, int find_unused)
   8.827 +void vnc_display_init(DisplayState *ds)
   8.828  {
   8.829 -    struct sockaddr *addr;
   8.830 -    struct sockaddr_in iaddr;
   8.831 -#ifndef _WIN32
   8.832 -    struct sockaddr_un uaddr;
   8.833 -#endif
   8.834 -    int reuse_addr, ret;
   8.835 -    socklen_t addrlen;
   8.836 -    const char *p;
   8.837      VncState *vs;
   8.838  
   8.839      vs = qemu_mallocz(sizeof(VncState));
   8.840 @@ -1446,7 +2155,8 @@ int vnc_display_init(DisplayState *ds, c
   8.841  
   8.842      ds->opaque = vs;
   8.843      vnc_state = vs;
   8.844 -    vs->display = arg;
   8.845 +    vs->display = NULL;
   8.846 +    vs->password = NULL;
   8.847  
   8.848      vs->lsock = -1;
   8.849      vs->csock = -1;
   8.850 @@ -1470,19 +2180,238 @@ int vnc_display_init(DisplayState *ds, c
   8.851      vs->ds->dpy_refresh = vnc_dpy_refresh;
   8.852  
   8.853      vnc_dpy_resize(vs->ds, 640, 400);
   8.854 +}
   8.855  
   8.856 -    if (arg == NULL)
   8.857 -	arg = "localhost:0";
   8.858 -    
   8.859 +#if CONFIG_VNC_TLS
   8.860 +static int vnc_set_x509_credential(VncState *vs,
   8.861 +				   const char *certdir,
   8.862 +				   const char *filename,
   8.863 +				   char **cred,
   8.864 +				   int ignoreMissing)
   8.865 +{
   8.866 +    struct stat sb;
   8.867 +
   8.868 +    if (*cred) {
   8.869 +	qemu_free(*cred);
   8.870 +	*cred = NULL;
   8.871 +    }
   8.872 +
   8.873 +    if (!(*cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2)))
   8.874 +	return -1;
   8.875 +
   8.876 +    strcpy(*cred, certdir);
   8.877 +    strcat(*cred, "/");
   8.878 +    strcat(*cred, filename);
   8.879 +
   8.880 +    VNC_DEBUG("Check %s\n", *cred);
   8.881 +    if (stat(*cred, &sb) < 0) {
   8.882 +	qemu_free(*cred);
   8.883 +	*cred = NULL;
   8.884 +	if (ignoreMissing && errno == ENOENT)
   8.885 +	    return 0;
   8.886 +	return -1;
   8.887 +    }
   8.888 +
   8.889 +    return 0;
   8.890 +}
   8.891 +
   8.892 +static int vnc_set_x509_credential_dir(VncState *vs,
   8.893 +				       const char *certdir)
   8.894 +{
   8.895 +    if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0)
   8.896 +	goto cleanup;
   8.897 +    if (vnc_set_x509_credential(vs, certdir, X509_CA_CRL_FILE, &vs->x509cacrl, 1) < 0)
   8.898 +	goto cleanup;
   8.899 +    if (vnc_set_x509_credential(vs, certdir, X509_SERVER_CERT_FILE, &vs->x509cert, 0) < 0)
   8.900 +	goto cleanup;
   8.901 +    if (vnc_set_x509_credential(vs, certdir, X509_SERVER_KEY_FILE, &vs->x509key, 0) < 0)
   8.902 +	goto cleanup;
   8.903 +
   8.904 +    return 0;
   8.905 +
   8.906 + cleanup:
   8.907 +    qemu_free(vs->x509cacert);
   8.908 +    qemu_free(vs->x509cacrl);
   8.909 +    qemu_free(vs->x509cert);
   8.910 +    qemu_free(vs->x509key);
   8.911 +    vs->x509cacert = vs->x509cacrl = vs->x509cert = vs->x509key = NULL;
   8.912 +    return -1;
   8.913 +}
   8.914 +#endif /* CONFIG_VNC_TLS */
   8.915 +
   8.916 +void vnc_display_close(DisplayState *ds)
   8.917 +{
   8.918 +    VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
   8.919 +
   8.920 +    if (vs->display) {
   8.921 +	qemu_free(vs->display);
   8.922 +	vs->display = NULL;
   8.923 +    }
   8.924 +    if (vs->lsock != -1) {
   8.925 +	qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
   8.926 +	close(vs->lsock);
   8.927 +	vs->lsock = -1;
   8.928 +    }
   8.929 +    if (vs->csock != -1) {
   8.930 +	qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
   8.931 +	closesocket(vs->csock);
   8.932 +	vs->csock = -1;
   8.933 +	buffer_reset(&vs->input);
   8.934 +	buffer_reset(&vs->output);
   8.935 +#if CONFIG_VNC_TLS
   8.936 +	if (vs->tls_session) {
   8.937 +	    gnutls_deinit(vs->tls_session);
   8.938 +	    vs->tls_session = NULL;
   8.939 +	}
   8.940 +	vs->wiremode = VNC_WIREMODE_CLEAR;
   8.941 +#endif /* CONFIG_VNC_TLS */
   8.942 +    }
   8.943 +    vs->auth = VNC_AUTH_INVALID;
   8.944 +#if CONFIG_VNC_TLS
   8.945 +    vs->subauth = VNC_AUTH_INVALID;
   8.946 +    vs->x509verify = 0;
   8.947 +#endif
   8.948 +}
   8.949 +
   8.950 +int parse_host_port(struct sockaddr_in *saddr, const char *str);
   8.951 +
   8.952 +
   8.953 +
   8.954 +int vnc_display_password(DisplayState *ds, const char *password)
   8.955 +{
   8.956 +    VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
   8.957 +
   8.958 +    if (vs->password) {
   8.959 +	qemu_free(vs->password);
   8.960 +	vs->password = NULL;
   8.961 +    }
   8.962 +    if (password && password[0]) {
   8.963 +	if (!(vs->password = qemu_strdup(password)))
   8.964 +	    return -1;
   8.965 +    }
   8.966 +
   8.967 +    return 0;
   8.968 +}
   8.969 +
   8.970 +int vnc_display_open(DisplayState *ds, const char *display, int find_unused)
   8.971 +{
   8.972 +    struct sockaddr *addr;
   8.973 +    struct sockaddr_in iaddr;
   8.974  #ifndef _WIN32
   8.975 -    if (strstart(arg, "unix:", &p)) {
   8.976 +    struct sockaddr_un uaddr;
   8.977 +#endif
   8.978 +    int reuse_addr, ret;
   8.979 +    socklen_t addrlen;
   8.980 +    const char *p;
   8.981 +    VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
   8.982 +    const char *options;
   8.983 +    int password = 0;
   8.984 +#if CONFIG_VNC_TLS
   8.985 +    int tls = 0, x509 = 0;
   8.986 +#endif
   8.987 +
   8.988 +    if (display == NULL)
   8.989 +	display = "localhost:0";
   8.990 +
   8.991 +    vnc_display_close(ds);
   8.992 +    if (strcmp(display, "none") == 0)
   8.993 +        return 0;
   8.994 +
   8.995 +    if (!(vs->display = strdup(display)))
   8.996 +        return -1;
   8.997 +
   8.998 +    options = display;
   8.999 +    while ((options = strchr(options, ','))) {
  8.1000 +	options++;
  8.1001 +	if (strncmp(options, "password", 8) == 0) {
  8.1002 +	    password = 1; /* Require password auth */
  8.1003 +#if CONFIG_VNC_TLS
  8.1004 +	} else if (strncmp(options, "tls", 3) == 0) {
  8.1005 +	    tls = 1; /* Require TLS */
  8.1006 +	} else if (strncmp(options, "x509", 4) == 0) {
  8.1007 +	    char *start, *end;
  8.1008 +	    x509 = 1; /* Require x509 certificates */
  8.1009 +	    if (strncmp(options, "x509verify", 10) == 0)
  8.1010 +	        vs->x509verify = 1; /* ...and verify client certs */
  8.1011 +
  8.1012 +	    /* Now check for 'x509=/some/path' postfix
  8.1013 +	     * and use that to setup x509 certificate/key paths */
  8.1014 +	    start = strchr(options, '=');
  8.1015 +	    end = strchr(options, ',');
  8.1016 +	    if (start && (!end || (start < end))) {
  8.1017 +		int len = end ? end-(start+1) : strlen(start+1);
  8.1018 +		char *path = qemu_malloc(len+1);
  8.1019 +		strncpy(path, start+1, len);
  8.1020 +		path[len] = '\0';
  8.1021 +		VNC_DEBUG("Trying certificate path '%s'\n", path);
  8.1022 +		if (vnc_set_x509_credential_dir(vs, path) < 0) {
  8.1023 +		    fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
  8.1024 +		    qemu_free(path);
  8.1025 +		    qemu_free(vs->display);
  8.1026 +		    vs->display = NULL;
  8.1027 +		    return -1;
  8.1028 +		}
  8.1029 +		qemu_free(path);
  8.1030 +	    } else {
  8.1031 +		fprintf(stderr, "No certificate path provided\n");
  8.1032 +		qemu_free(vs->display);
  8.1033 +		vs->display = NULL;
  8.1034 +		return -1;
  8.1035 +	    }
  8.1036 +#endif
  8.1037 +	}
  8.1038 +    }
  8.1039 +
  8.1040 +    if (password) {
  8.1041 +#if CONFIG_VNC_TLS
  8.1042 +	if (tls) {
  8.1043 +	    vs->auth = VNC_AUTH_VENCRYPT;
  8.1044 +	    if (x509) {
  8.1045 +		VNC_DEBUG("Initializing VNC server with x509 password auth\n");
  8.1046 +		vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
  8.1047 +	    } else {
  8.1048 +		VNC_DEBUG("Initializing VNC server with TLS password auth\n");
  8.1049 +		vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
  8.1050 +	    }
  8.1051 +	} else {
  8.1052 +#endif
  8.1053 +	    VNC_DEBUG("Initializing VNC server with password auth\n");
  8.1054 +	    vs->auth = VNC_AUTH_VNC;
  8.1055 +#if CONFIG_VNC_TLS
  8.1056 +	    vs->subauth = VNC_AUTH_INVALID;
  8.1057 +	}
  8.1058 +#endif
  8.1059 +    } else {
  8.1060 +#if CONFIG_VNC_TLS
  8.1061 +	if (tls) {
  8.1062 +	    vs->auth = VNC_AUTH_VENCRYPT;
  8.1063 +	    if (x509) {
  8.1064 +		VNC_DEBUG("Initializing VNC server with x509 no auth\n");
  8.1065 +		vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
  8.1066 +	    } else {
  8.1067 +		VNC_DEBUG("Initializing VNC server with TLS no auth\n");
  8.1068 +		vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
  8.1069 +	    }
  8.1070 +	} else {
  8.1071 +#endif
  8.1072 +	    VNC_DEBUG("Initializing VNC server with no auth\n");
  8.1073 +	    vs->auth = VNC_AUTH_NONE;
  8.1074 +#if CONFIG_VNC_TLS
  8.1075 +	    vs->subauth = VNC_AUTH_INVALID;
  8.1076 +	}
  8.1077 +#endif
  8.1078 +    }
  8.1079 +#ifndef _WIN32
  8.1080 +    if (strstart(display, "unix:", &p)) {
  8.1081  	addr = (struct sockaddr *)&uaddr;
  8.1082  	addrlen = sizeof(uaddr);
  8.1083  
  8.1084  	vs->lsock = socket(PF_UNIX, SOCK_STREAM, 0);
  8.1085  	if (vs->lsock == -1) {
  8.1086  	    fprintf(stderr, "Could not create socket\n");
  8.1087 -	    exit(1);
  8.1088 +	    free(vs->display);
  8.1089 +	    vs->display = NULL;
  8.1090 +	    return -1;
  8.1091  	}
  8.1092  
  8.1093  	uaddr.sun_family = AF_UNIX;
  8.1094 @@ -1496,25 +2425,33 @@ int vnc_display_init(DisplayState *ds, c
  8.1095  	addr = (struct sockaddr *)&iaddr;
  8.1096  	addrlen = sizeof(iaddr);
  8.1097  
  8.1098 +	if (parse_host_port(&iaddr, display) < 0) {
  8.1099 +	    fprintf(stderr, "Could not parse VNC address\n");
  8.1100 +	    free(vs->display);
  8.1101 +	    vs->display = NULL;
  8.1102 +	    return -1;
  8.1103 +	}
  8.1104 +
  8.1105 +	iaddr.sin_port = htons(ntohs(iaddr.sin_port) + 5900);
  8.1106 +
  8.1107  	vs->lsock = socket(PF_INET, SOCK_STREAM, 0);
  8.1108  	if (vs->lsock == -1) {
  8.1109  	    fprintf(stderr, "Could not create socket\n");
  8.1110 -	    exit(1);
  8.1111 +	    free(vs->display);
  8.1112 +	    vs->display = NULL;
  8.1113 +	    return -1;
  8.1114  	}
  8.1115  
  8.1116 -	if (parse_host_port(&iaddr, arg) < 0) {
  8.1117 -	    fprintf(stderr, "Could not parse VNC address\n");
  8.1118 -	    exit(1);
  8.1119 -	}
  8.1120 -	    
  8.1121 -	iaddr.sin_port = htons(ntohs(iaddr.sin_port) + 5900);
  8.1122 -
  8.1123  	reuse_addr = 1;
  8.1124  	ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR,
  8.1125  			 (const char *)&reuse_addr, sizeof(reuse_addr));
  8.1126  	if (ret == -1) {
  8.1127  	    fprintf(stderr, "setsockopt() failed\n");
  8.1128 -	    exit(1);
  8.1129 +	    close(vs->lsock);
  8.1130 +	    vs->lsock = -1;
  8.1131 +	    free(vs->display);
  8.1132 +	    vs->display = NULL;
  8.1133 +	    return -1;
  8.1134  	}
  8.1135      }
  8.1136  
  8.1137 @@ -1524,18 +2461,24 @@ int vnc_display_init(DisplayState *ds, c
  8.1138  	    continue;
  8.1139  	}
  8.1140  	fprintf(stderr, "bind() failed\n");
  8.1141 -	exit(1);
  8.1142 +	close(vs->lsock);
  8.1143 +	vs->lsock = -1;
  8.1144 +	free(vs->display);
  8.1145 +	vs->display = NULL;
  8.1146 +	return -1;
  8.1147      }
  8.1148  
  8.1149      if (listen(vs->lsock, 1) == -1) {
  8.1150  	fprintf(stderr, "listen() failed\n");
  8.1151 -	exit(1);
  8.1152 +	close(vs->lsock);
  8.1153 +	vs->lsock = -1;
  8.1154 +	free(vs->display);
  8.1155 +	vs->display = NULL;
  8.1156 +	return -1;
  8.1157      }
  8.1158  
  8.1159 -    ret = qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs);
  8.1160 -    if (ret == -1) {
  8.1161 -	exit(1);
  8.1162 -    }
  8.1163 +    if (qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs) < 0)
  8.1164 +	return -1;
  8.1165  
  8.1166      return ntohs(iaddr.sin_port);
  8.1167  }
     9.1 --- a/tools/ioemu/xenstore.c	Tue Oct 30 09:24:17 2007 +0000
     9.2 +++ b/tools/ioemu/xenstore.c	Tue Oct 30 09:30:49 2007 +0000
     9.3 @@ -515,6 +515,7 @@ int xenstore_read_vncpasswd(int domid, c
     9.4      passwd = xs_read(xsh, XBT_NULL, buf, &len);
     9.5      if (passwd == NULL) {
     9.6          fprintf(logfile, "xs_read(): vncpasswd get error. %s.\n", buf);
     9.7 +        pwbuf[0] = '\0';
     9.8          free(uuid);
     9.9          free(path);
    9.10          return rc;
    10.1 --- a/tools/python/xen/xend/image.py	Tue Oct 30 09:24:17 2007 +0000
    10.2 +++ b/tools/python/xen/xend/image.py	Tue Oct 30 09:30:49 2007 +0000
    10.3 @@ -31,6 +31,7 @@ from xen.xend.XendOptions import instanc
    10.4  from xen.xend.xenstore.xstransact import xstransact
    10.5  from xen.xend.xenstore.xswatch import xswatch
    10.6  from xen.xend import arch
    10.7 +from xen.xend import XendOptions
    10.8  
    10.9  xc = xen.lowlevel.xc.xc()
   10.10  
   10.11 @@ -214,27 +215,27 @@ class ImageHandler:
   10.12                              'vncpasswd'):
   10.13                      if key in vmConfig['platform']:
   10.14                          vnc_config[key] = vmConfig['platform'][key]
   10.15 +            if vnc_config.has_key("vncpasswd"):
   10.16 +                passwd = vnc_config["vncpasswd"]
   10.17 +            else:
   10.18 +                passwd = XendOptions.instance().get_vncpasswd_default()
   10.19 +            vncopts = ""
   10.20 +            if passwd:
   10.21 +                self.vm.storeVm("vncpasswd", passwd)
   10.22 +                vncopts = vncopts + ",password"
   10.23 +                log.debug("Stored a VNC password for vfb access")
   10.24 +            else:
   10.25 +                log.debug("No VNC passwd configured for vfb access")
   10.26  
   10.27              vnclisten = vnc_config.get('vnclisten',
   10.28 -                                       xenopts().get_vnclisten_address())
   10.29 +                                       XendOptions.instance().get_vnclisten_address())
   10.30              vncdisplay = vnc_config.get('vncdisplay', 0)
   10.31              ret.append('-vnc')
   10.32 -            ret.append("%s:%s" % (vnclisten, vncdisplay))
   10.33 -            
   10.34 +            ret.append("%s:%s%s" % (vnclisten, vncdisplay, vncopts))
   10.35 +
   10.36              if vnc_config.get('vncunused', 0):
   10.37                  ret.append('-vncunused')
   10.38  
   10.39 -            # Store vncpassword in xenstore
   10.40 -            vncpasswd = vnc_config.get('vncpasswd')
   10.41 -            if not vncpasswd:
   10.42 -                vncpasswd = xenopts().get_vncpasswd_default()
   10.43 -
   10.44 -            if vncpasswd is None:
   10.45 -                raise VmError('vncpasswd is not setup in vmconfig or '
   10.46 -                              'xend-config.sxp')
   10.47 -
   10.48 -            if vncpasswd != '':
   10.49 -                self.vm.storeVm('vncpasswd', vncpasswd)
   10.50          elif has_sdl:
   10.51              # SDL is default in QEMU.
   10.52              pass