Index: head/usr.sbin/bhyve/Makefile
===================================================================
--- head/usr.sbin/bhyve/Makefile	(revision 319486)
+++ head/usr.sbin/bhyve/Makefile	(revision 319487)
@@ -1,72 +1,80 @@
 #
 # $FreeBSD$
 #
 
+.include <src.opts.mk>
+
 PROG=	bhyve
 PACKAGE=	bhyve
 
 DEBUG_FLAGS= -g -O0
 
 MAN=	bhyve.8
 
 BHYVE_SYSDIR?=${SRCTOP}
 
 SRCS=	\
 	atkbdc.c		\
 	acpi.c			\
 	bhyvegc.c		\
 	bhyverun.c		\
 	block_if.c		\
 	bootrom.c		\
 	console.c		\
 	consport.c		\
 	dbgport.c		\
 	fwctl.c			\
 	inout.c			\
 	ioapic.c		\
 	mem.c			\
 	mevent.c		\
 	mptbl.c			\
 	pci_ahci.c		\
 	pci_e82545.c		\
 	pci_emul.c		\
 	pci_fbuf.c		\
 	pci_hostbridge.c	\
 	pci_irq.c		\
 	pci_lpc.c		\
 	pci_passthru.c		\
 	pci_virtio_block.c	\
 	pci_virtio_console.c	\
 	pci_virtio_net.c	\
 	pci_virtio_rnd.c	\
 	pci_uart.c		\
 	pci_xhci.c		\
 	pm.c			\
 	post.c			\
 	ps2kbd.c		\
 	ps2mouse.c		\
 	rfb.c			\
 	rtc.c			\
 	smbiostbl.c		\
 	sockstream.c		\
 	task_switch.c		\
 	uart_emul.c		\
 	usb_emul.c		\
 	usb_mouse.c		\
 	virtio.c		\
 	vga.c			\
 	xmsr.c			\
 	spinup_ap.c
 
 .PATH:  ${BHYVE_SYSDIR}/sys/amd64/vmm
 SRCS+=	vmm_instruction_emul.c
 
 LIBADD=	vmmapi md pthread z
+
+.if ${MK_OPENSSL} == "no"
+CFLAGS+=-DNO_OPENSSL
+.else
+LIBADD+=	crypto
+.endif
 
 CFLAGS+= -I${BHYVE_SYSDIR}/sys/dev/e1000
 CFLAGS+= -I${BHYVE_SYSDIR}/sys/dev/mii
 CFLAGS+= -I${BHYVE_SYSDIR}/sys/dev/usb/controller
 
 WARNS?=	2
 
 .include <bsd.prog.mk>
Index: head/usr.sbin/bhyve/bhyve.8
===================================================================
--- head/usr.sbin/bhyve/bhyve.8	(revision 319486)
+++ head/usr.sbin/bhyve/bhyve.8	(revision 319487)
@@ -1,499 +1,504 @@
 .\" Copyright (c) 2013 Peter Grehan
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
 .\" modification, are permitted provided that the following conditions
 .\" are met:
 .\" 1. Redistributions of source code must retain the above copyright
 .\"    notice, this list of conditions and the following disclaimer.
 .\" 2. Redistributions in binary form must reproduce the above copyright
 .\"    notice, this list of conditions and the following disclaimer in the
 .\"    documentation and/or other materials provided with the distribution.
 .\"
 .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 .\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
 .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
 .\" $FreeBSD$
 .\"
-.Dd May 3, 2017
+.Dd May 22, 2017
 .Dt BHYVE 8
 .Os
 .Sh NAME
 .Nm bhyve
 .Nd "run a guest operating system inside a virtual machine"
 .Sh SYNOPSIS
 .Nm
 .Op Fl abehuwxACHPSWY
 .Op Fl c Ar numcpus
 .Op Fl g Ar gdbport
 .Op Fl l Ar lpcdev Ns Op , Ns Ar conf
 .Op Fl m Ar memsize Ns Op Ar K|k|M|m|G|g|T|t
 .Op Fl p Ar vcpu:hostcpu
 .Op Fl s Ar slot,emulation Ns Op , Ns Ar conf
 .Op Fl U Ar uuid
 .Ar vmname
 .Sh DESCRIPTION
 .Nm
 is a hypervisor that runs guest operating systems inside a
 virtual machine.
 .Pp
 Parameters such as the number of virtual CPUs, amount of guest memory, and
 I/O connectivity can be specified with command-line parameters.
 .Pp
 If not using a boot ROM, the guest operating system must be loaded with
 .Xr bhyveload 8
 or a similar boot loader before running
 .Nm ,
 otherwise, it is enough to run
 .Nm
 with a boot ROM of choice.
 .Pp
 .Nm
 runs until the guest operating system reboots or an unhandled hypervisor
 exit is detected.
 .Sh OPTIONS
 .Bl -tag -width 10n
 .It Fl a
 The guest's local APIC is configured in xAPIC mode.
 The xAPIC mode is the default setting so this option is redundant.
 It will be deprecated in a future version.
 .It Fl A
 Generate ACPI tables.
 Required for
 .Fx Ns /amd64
 guests.
 .It Fl b
 Enable a low-level console device supported by
 .Fx
 kernels compiled with
 .Cd "device bvmconsole" .
 This option will be deprecated in a future version.
 .It Fl c Ar numcpus
 Number of guest virtual CPUs.
 The default is 1 and the maximum is 16.
 .It Fl C
 Include guest memory in core file.
 .It Fl e
 Force
 .Nm
 to exit when a guest issues an access to an I/O port that is not emulated.
 This is intended for debug purposes.
 .It Fl g Ar gdbport
 For
 .Fx
 kernels compiled with
 .Cd "device bvmdebug" ,
 allow a remote kernel kgdb to be relayed to the guest kernel gdb stub
 via a local IPv4 address and this port.
 This option will be deprecated in a future version.
 .It Fl h
 Print help message and exit.
 .It Fl H
 Yield the virtual CPU thread when a HLT instruction is detected.
 If this option is not specified, virtual CPUs will use 100% of a host CPU.
 .It Fl l Ar lpcdev Ns Op , Ns Ar conf
 Allow devices behind the LPC PCI-ISA bridge to be configured.
 The only supported devices are the TTY-class devices
 .Ar com1
 and
 .Ar com2
 and the boot ROM device
 .Ar bootrom .
 .It Fl m Ar memsize Ns Op Ar K|k|M|m|G|g|T|t
 Guest physical memory size in bytes.
 This must be the same size that was given to
 .Xr bhyveload 8 .
 .Pp
 The size argument may be suffixed with one of K, M, G or T (either upper
 or lower case) to indicate a multiple of kilobytes, megabytes, gigabytes,
 or terabytes.
 If no suffix is given, the value is assumed to be in megabytes.
 .Pp
 .Ar memsize
 defaults to 256M.
 .It Fl p Ar vcpu:hostcpu
 Pin guest's virtual CPU
 .Em vcpu
 to
 .Em hostcpu .
 .It Fl P
 Force the guest virtual CPU to exit when a PAUSE instruction is detected.
 .It Fl s Ar slot,emulation Ns Op , Ns Ar conf
 Configure a virtual PCI slot and function.
 .Pp
 .Nm
 provides PCI bus emulation and virtual devices that can be attached to
 slots on the bus.
 There are 32 available slots, with the option of providing up to 8 functions
 per slot.
 .Bl -tag -width 10n
 .It Ar slot
 .Ar pcislot[:function]
 .Ar bus:pcislot:function
 .Pp
 The
 .Ar pcislot
 value is 0 to 31.
 The optional
 .Ar function
 value is 0 to 7.
 The optional
 .Ar bus
 value is 0 to 255.
 If not specified, the
 .Ar function
 value defaults to 0.
 If not specified, the
 .Ar bus
 value defaults to 0.
 .It Ar emulation
 .Bl -tag -width 10n
 .It Li hostbridge | Li amd_hostbridge
 .Pp
 Provide a simple host bridge.
 This is usually configured at slot 0, and is required by most guest
 operating systems.
 The
 .Li amd_hostbridge
 emulation is identical but uses a PCI vendor ID of
 .Li AMD .
 .It Li passthru
 PCI pass-through device.
 .It Li virtio-net
 Virtio network interface.
 .It Li virtio-blk
 Virtio block storage interface.
 .It Li virtio-rnd
 Virtio RNG interface.
 .It Li virtio-console
 Virtio console interface, which exposes multiple ports
 to the guest in the form of simple char devices for simple IO
 between the guest and host userspaces.
 .It Li ahci
 AHCI controller attached to arbitrary devices.
 .It Li ahci-cd
 AHCI controller attached to an ATAPI CD/DVD.
 .It Li ahci-hd
 AHCI controller attached to a SATA hard-drive.
 .It Li e1000
 Intel e82545 network interface.
 .It Li uart
 PCI 16550 serial device.
 .It Li lpc
 LPC PCI-ISA bridge with COM1 and COM2 16550 serial ports and a boot ROM.
 The LPC bridge emulation can only be configured on bus 0.
 .It Li fbuf
 Raw framebuffer device attached to VNC server.
 .It Li xhci
 eXtensible Host Controller Interface (xHCI) USB controller.
 .El
 .It Op Ar conf
 This optional parameter describes the backend for device emulations.
 If
 .Ar conf
 is not specified, the device emulation has no backend and can be
 considered unconnected.
 .Pp
 Network devices:
 .Bl -tag -width 10n
 .It Ar tapN Ns Op , Ns Ar mac=xx:xx:xx:xx:xx:xx
 .It Ar vmnetN Ns Op , Ns Ar mac=xx:xx:xx:xx:xx:xx
 .Pp
 If
 .Ar mac
 is not specified, the MAC address is derived from a fixed OUI and the
 remaining bytes from an MD5 hash of the slot and function numbers and
 the device name.
 .Pp
 The MAC address is an ASCII string in
 .Xr ethers 5
 format.
 .El
 .Pp
 Block storage devices:
 .Bl -tag -width 10n
 .It Pa /filename Ns Oo , Ns Ar block-device-options Oc
 .It Pa /dev/xxx Ns Oo , Ns Ar block-device-options Oc
 .El
 .Pp
 The
 .Ar block-device-options
 are:
 .Bl -tag -width 8n
 .It Li nocache
 Open the file with
 .Dv O_DIRECT .
 .It Li direct
 Open the file using
 .Dv O_SYNC .
 .It Li ro
 Force the file to be opened read-only.
 .It Li sectorsize= Ns Ar logical Ns Oo / Ns Ar physical Oc
 Specify the logical and physical sector sizes of the emulated disk.
 The physical sector size is optional and is equal to the logical sector size
 if not explicitly specified.
 .El
 .Pp
 TTY devices:
 .Bl -tag -width 10n
 .It Li stdio
 Connect the serial port to the standard input and output of
 the
 .Nm
 process.
 .It Pa /dev/xxx
 Use the host TTY device for serial port I/O.
 .El
 .Pp
 Boot ROM device:
 .Bl -tag -width 10n
 .It Pa romfile
 Map
 .Ar romfile
 in the guest address space reserved for boot firmware.
 .El
 .Pp
 Pass-through devices:
 .Bl -tag -width 10n
 .It Ns Ar slot Ns / Ns Ar bus Ns / Ns Ar function
 Connect to a PCI device on the host at the selector described by
 .Ar slot ,
 .Ar bus ,
 and
 .Ar function
 numbers.
 .El
 .Pp
 Guest memory must be wired using the
 .Fl S
 option when a pass-through device is configured.
 .Pp
 The host device must have been reserved at boot-time using the
 .Va pptdev
 loader variable as described in
 .Xr vmm 4 .
 .Pp
 Virtio console devices:
 .Bl -tag -width 10n
 .It Li port1= Ns Pa /path/to/port1.sock Ns ,anotherport= Ns Pa ...
 A maximum of 16 ports per device can be created.
 Every port is named and corresponds to a Unix domain socket created by
 .Nm .
 .Nm
 accepts at most one connection per port at a time.
 .Pp
 Limitations:
 .Bl -bullet -offset 2n
 .It
 Due to lack of destructors in
 .Nm ,
 sockets on the filesystem must be cleaned up manually after
 .Nm
 exits.
 .It
 There is no way to use the "console port" feature, nor the console port
 resize at present.
 .It
 Emergency write is advertised, but no-op at present.
 .El
 .El
 .Pp
 Framebuffer devices:
 .Bl -tag -width 10n
-.It Oo rfb= Ns Oo Ar IP: Oc Ns Ar port Oc Ns Oo ,w= Ns Ar width Oc Ns Oo ,h= Ns Ar height Oc Ns Oo ,vga= Ns Ar vgaconf Oc Ns Oo Ns ,wait Oc
+.It Oo rfb= Ns Oo Ar IP: Oc Ns Ar port Oc Ns Oo ,w= Ns Ar width Oc Ns Oo ,h= Ns Ar height Oc Ns Oo ,vga= Ns Ar vgaconf Oc Ns Oo Ns ,wait Oc Ns Oo ,password= Ns Ar password Oc
 .Bl -tag -width 8n
 .It Ar IP:port
 An
 .Ar IP
 address and a
 .Ar port
 VNC should listen on.
 The default is to listen on localhost IPv4 address and default VNC port 5900.
 Listening on an IPv6 address is not supported.
 .It Ar width No and Ar height
 A display resolution, width and height, respectively.
 If not specified, a default resolution of 1024x768 pixels will be used.
 Minimal supported resolution is 640x480 pixels,
 and maximum is 1920x1200 pixels.
 .It Ar vgaconf
 Possible values for this option are
 .Dq io
 (default),
 .Dq on
 , and
 .Dq off .
 PCI graphics cards have a dual personality in that they are
 standard PCI devices with BAR addressing, but may also
 implicitly decode legacy VGA I/O space
 .Pq Ad 0x3c0-3df
 and memory space
 .Pq 64KB at Ad 0xA0000 .
 The default
 .Dq io
 option should be used for guests that attempt to issue BIOS
 calls which result in I/O port queries, and fail to boot if I/O decode is disabled.
 .Pp
 The
 .Dq on
 option should be used along with the CSM BIOS capability in UEFI
 to boot traditional BIOS guests that require the legacy VGA I/O and
 memory regions to be available.
 .Pp
 The
 .Dq off
 option should be used for the UEFI guests that assume that
 VGA adapter is present if they detect the I/O ports.
 An example of such a guest is
 .Ox
 in UEFI mode.
 .Pp
 Please refer to the
 .Nm
 .Fx
 wiki page
 .Pq Lk https://wiki.freebsd.org/bhyve
 for configuration notes of particular guests.
 .It wait
 Instruct
 .Nm
 to only boot upon the initiation of a VNC connection, simplifying the installation
 of operating systems that require immediate keyboard input.
 This can be removed for post-installation use.
+.It password
+This type of authentication is known to be cryptographically weak and is not
+intended for use on untrusted networks.
+Many implementations will want to use stronger security, such as running
+the session over an encrypted channel provided by IPsec or SSH.
 .El
 .El
 .Pp
 xHCI USB devices:
 .Bl -tag -width 10n
 .It Li tablet
 A USB tablet device which provides precise cursor synchronization
 when using VNC.
 .El
 .El
 .It Fl S
 Wire guest memory.
 .It Fl u
 RTC keeps UTC time.
 .It Fl U Ar uuid
 Set the universally unique identifier
 .Pq UUID
 in the guest's System Management BIOS System Information structure.
 By default a UUID is generated from the host's hostname and
 .Ar vmname .
 .It Fl w
 Ignore accesses to unimplemented Model Specific Registers (MSRs).
 This is intended for debug purposes.
 .It Fl W
 Force virtio PCI device emulations to use MSI interrupts instead of MSI-X
 interrupts.
 .It Fl x
 The guest's local APIC is configured in x2APIC mode.
 .It Fl Y
 Disable MPtable generation.
 .It Ar vmname
 Alphanumeric name of the guest.
 This should be the same as that created by
 .Xr bhyveload 8 .
 .El
 .Sh SIGNAL HANDLING
 .Nm
 deals with the following signals:
 .Pp
 .Bl -tag -width indent -compact
 .It SIGTERM
 Trigger ACPI poweroff for a VM
 .El
 .Sh EXIT STATUS
 Exit status indicates how the VM was terminated:
 .Pp
 .Bl -tag -width indent -compact
 .It 0
 rebooted
 .It 1
 powered off
 .It 2
 halted
 .It 3
 triple fault
 .El
 .Sh EXAMPLES
 If not using a boot ROM, the guest operating system must have been loaded with
 .Xr bhyveload 8
 or a similar boot loader before
 .Xr bhyve 4
 can be run.
 Otherwise, the boot loader is not needed.
 .Pp
 To run a virtual machine with 1GB of memory, two virtual CPUs, a virtio
 block device backed by the
 .Pa /my/image
 filesystem image, and a serial port for the console:
 .Bd -literal -offset indent
 bhyve -c 2 -s 0,hostbridge -s 1,lpc -s 2,virtio-blk,/my/image \\
   -l com1,stdio -A -H -P -m 1G vm1
 .Ed
 .Pp
 Run a 24GB single-CPU virtual machine with three network ports, one of which
 has a MAC address specified:
 .Bd -literal -offset indent
 bhyve -s 0,hostbridge -s 1,lpc -s 2:0,virtio-net,tap0 \\
   -s 2:1,virtio-net,tap1 \\
   -s 2:2,virtio-net,tap2,mac=00:be:fa:76:45:00 \\
   -s 3,virtio-blk,/my/image -l com1,stdio \\
   -A -H -P -m 24G bigvm
 .Ed
 .Pp
 Run an 8GB quad-CPU virtual machine with 8 AHCI SATA disks, an AHCI ATAPI
 CD-ROM, a single virtio network port, an AMD hostbridge, and the console
 port connected to an
 .Xr nmdm 4
 null-modem device.
 .Bd -literal -offset indent
 bhyve -c 4 \\
   -s 0,amd_hostbridge -s 1,lpc \\
   -s 1:0,ahci,hd:/images/disk.1,hd:/images/disk.2,\\
 hd:/images/disk.3,hd:/images/disk.4,\\
 hd:/images/disk.5,hd:/images/disk.6,\\
 hd:/images/disk.7,hd:/images/disk.8,\\
 cd:/images/install.iso \\
   -s 3,virtio-net,tap0 \\
   -l com1,/dev/nmdm0A \\
   -A -H -P -m 8G
 .Ed
 .Pp
 Run a UEFI virtual machine with a display resolution of 800 by 600 pixels
 that can be accessed via VNC at: 0.0.0.0:5900.
 .Bd -literal -offset indent
 bhyve -c 2 -m 4G -w -H \\
   -s 0,hostbridge \\
   -s 3,ahci-cd,/path/to/uefi-OS-install.iso \\
   -s 4,ahci-hd,disk.img \\
   -s 5,virtio-net,tap0 \\
   -s 29,fbuf,tcp=0.0.0.0:5900,w=800,h=600,wait \\
   -s 30,xhci,tablet \\
   -s 31,lpc -l com1,stdio \\
   -l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \\
    uefivm
 .Ed
 .Sh SEE ALSO
 .Xr bhyve 4 ,
 .Xr nmdm 4 ,
 .Xr vmm 4 ,
 .Xr ethers 5 ,
 .Xr bhyvectl 8 ,
 .Xr bhyveload 8
 .Sh HISTORY
 .Nm
 first appeared in
 .Fx 10.0 .
 .Sh AUTHORS
 .An Neel Natu Aq Mt neel@freebsd.org
 .An Peter Grehan Aq Mt grehan@freebsd.org
Index: head/usr.sbin/bhyve/pci_fbuf.c
===================================================================
--- head/usr.sbin/bhyve/pci_fbuf.c	(revision 319486)
+++ head/usr.sbin/bhyve/pci_fbuf.c	(revision 319487)
@@ -1,424 +1,426 @@
 /*-
  * Copyright (c) 2015 Nahanni Systems, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * $FreeBSD$
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
 #include <sys/mman.h>
 
 #include <machine/vmm.h>
 #include <vmmapi.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include <errno.h>
 #include <unistd.h>
 
 #include "bhyvegc.h"
 #include "bhyverun.h"
 #include "console.h"
 #include "inout.h"
 #include "pci_emul.h"
 #include "rfb.h"
 #include "vga.h"
 
 /*
  * bhyve Framebuffer device emulation.
  * BAR0 points to the current mode information.
  * BAR1 is the 32-bit framebuffer address.
  *
  *  -s <b>,fbuf,wait,vga=on|io|off,rfb=<ip>:port,w=width,h=height
  */
 
 static int fbuf_debug = 1;
 #define	DEBUG_INFO	1
 #define	DEBUG_VERBOSE	4
 #define	DPRINTF(level, params)  if (level <= fbuf_debug) printf params
 
 
 #define	KB	(1024UL)
 #define	MB	(1024 * 1024UL)
 
 #define	DMEMSZ	128
 
 #define	FB_SIZE		(16*MB)
 
 #define COLS_MAX	1920
 #define	ROWS_MAX	1200
 
 #define COLS_DEFAULT	1024
 #define ROWS_DEFAULT	768
 
 #define COLS_MIN	640
 #define ROWS_MIN	480
 
 struct pci_fbuf_softc {
 	struct pci_devinst *fsc_pi;
 	struct {
 		uint32_t fbsize;
 		uint16_t width;
 		uint16_t height;
 		uint16_t depth;
 		uint16_t refreshrate;
 		uint8_t  reserved[116];
 	} __packed memregs;
 
 	/* rfb server */
 	char      *rfb_host;
+	char      *rfb_password;
 	int       rfb_port;
 	int       rfb_wait;
 	int       vga_enabled;
 	int	  vga_full;
 
 	uint32_t  fbaddr;
 	char      *fb_base;
 	uint16_t  gc_width;
 	uint16_t  gc_height;
 	void      *vgasc;
 	struct bhyvegc_image *gc_image;
 };
 
 static struct pci_fbuf_softc *fbuf_sc;
 
 #define	PCI_FBUF_MSI_MSGS	 4
 
 static void
 pci_fbuf_usage(char *opt)
 {
 
 	fprintf(stderr, "Invalid fbuf emulation \"%s\"\r\n", opt);
 	fprintf(stderr, "fbuf: {wait,}{vga=on|io|off,}rfb=<ip>:port\r\n");
 }
 
 static void
 pci_fbuf_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
 	       int baridx, uint64_t offset, int size, uint64_t value)
 {
 	struct pci_fbuf_softc *sc;
 	uint8_t *p;
 
 	assert(baridx == 0);
 
 	sc = pi->pi_arg;
 
 	DPRINTF(DEBUG_VERBOSE,
 	    ("fbuf wr: offset 0x%lx, size: %d, value: 0x%lx\n",
 	    offset, size, value));
 
 	if (offset + size > DMEMSZ) {
 		printf("fbuf: write too large, offset %ld size %d\n",
 		       offset, size);
 		return;
 	}
 
 	p = (uint8_t *)&sc->memregs + offset;
 
 	switch (size) {
 	case 1:
 		*p = value;
 		break;
 	case 2:
 		*(uint16_t *)p = value;
 		break;
 	case 4:
 		*(uint32_t *)p = value;
 		break;
 	case 8:
 		*(uint64_t *)p = value;
 		break;
 	default:
 		printf("fbuf: write unknown size %d\n", size);
 		break;
 	}
 
 	if (!sc->gc_image->vgamode && sc->memregs.width == 0 &&
 	    sc->memregs.height == 0) {
 		DPRINTF(DEBUG_INFO, ("switching to VGA mode\r\n"));
 		sc->gc_image->vgamode = 1;
 		sc->gc_width = 0;
 		sc->gc_height = 0;
 	} else if (sc->gc_image->vgamode && sc->memregs.width != 0 &&
 	    sc->memregs.height != 0) {
 		DPRINTF(DEBUG_INFO, ("switching to VESA mode\r\n"));
 		sc->gc_image->vgamode = 0;
 	}
 }
 
 uint64_t
 pci_fbuf_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
 	      int baridx, uint64_t offset, int size)
 {
 	struct pci_fbuf_softc *sc;
 	uint8_t *p;
 	uint64_t value;
 
 	assert(baridx == 0);
 
 	sc = pi->pi_arg;
 
 
 	if (offset + size > DMEMSZ) {
 		printf("fbuf: read too large, offset %ld size %d\n",
 		       offset, size);
 		return (0);
 	}
 
 	p = (uint8_t *)&sc->memregs + offset;
 	value = 0;
 	switch (size) {
 	case 1:
 		value = *p;
 		break;
 	case 2:
 		value = *(uint16_t *)p;
 		break;
 	case 4:
 		value = *(uint32_t *)p;
 		break;
 	case 8:
 		value = *(uint64_t *)p;
 		break;
 	default:
 		printf("fbuf: read unknown size %d\n", size);
 		break;
 	}
 
 	DPRINTF(DEBUG_VERBOSE,
 	    ("fbuf rd: offset 0x%lx, size: %d, value: 0x%lx\n",
 	     offset, size, value));
 
 	return (value);
 }
 
 static int
 pci_fbuf_parse_opts(struct pci_fbuf_softc *sc, char *opts)
 {
 	char	*uopts, *xopts, *config;
 	char	*tmpstr;
 	int	ret;
 
 	ret = 0;
 	uopts = strdup(opts);
 	for (xopts = strtok(uopts, ",");
 	     xopts != NULL;
 	     xopts = strtok(NULL, ",")) {
 		if (strcmp(xopts, "wait") == 0) {
 			sc->rfb_wait = 1;
 			continue;
 		}
 
 		if ((config = strchr(xopts, '=')) == NULL) {
 			pci_fbuf_usage(xopts);
 			ret = -1;
 			goto done;
 		}
 
 		*config++ = '\0';
 
 		DPRINTF(DEBUG_VERBOSE, ("pci_fbuf option %s = %s\r\n",
 		   xopts, config));
 
 		if (!strcmp(xopts, "tcp") || !strcmp(xopts, "rfb")) {
 			/* parse host-ip:port */
 		        tmpstr = strsep(&config, ":");
 			if (!config)
 				sc->rfb_port = atoi(tmpstr);
 			else {
 				sc->rfb_port = atoi(config);
 				sc->rfb_host = tmpstr;
 			}
 	        } else if (!strcmp(xopts, "vga")) {
 			if (!strcmp(config, "off")) {
 				sc->vga_enabled = 0;
 			} else if (!strcmp(config, "io")) {
 				sc->vga_enabled = 1;
 				sc->vga_full = 0;
 			} else if (!strcmp(config, "on")) {
 				sc->vga_enabled = 1;
 				sc->vga_full = 1;
 			} else {
 				pci_fbuf_usage(opts);
 				ret = -1;
 				goto done;
 			}
 	        } else if (!strcmp(xopts, "w")) {
 		        sc->memregs.width = atoi(config);
 			if (sc->memregs.width > COLS_MAX) {
 				pci_fbuf_usage(xopts);
 				ret = -1;
 				goto done;
 			} else if (sc->memregs.width == 0)
 				sc->memregs.width = 1920;
 		} else if (!strcmp(xopts, "h")) {
 			sc->memregs.height = atoi(config);
 			if (sc->memregs.height > ROWS_MAX) {
 				pci_fbuf_usage(xopts);
 				ret = -1;
 				goto done;
 			} else if (sc->memregs.height == 0)
 				sc->memregs.height = 1080;
-
+		} else if (!strcmp(xopts, "password")) {
+			sc->rfb_password = config;
 		} else {
 			pci_fbuf_usage(xopts);
 			ret = -1;
 			goto done;
 		}
 	}
 
 done:
 	return (ret);
 }
 
 
 extern void vga_render(struct bhyvegc *gc, void *arg);
 
 void
 pci_fbuf_render(struct bhyvegc *gc, void *arg)
 {
 	struct pci_fbuf_softc *sc;
 
 	sc = arg;
 
 	if (sc->vga_full && sc->gc_image->vgamode) {
 		/* TODO: mode switching to vga and vesa should use the special
 		 *      EFI-bhyve protocol port.
 		 */
 		vga_render(gc, sc->vgasc);
 		return;
 	}
 	if (sc->gc_width != sc->memregs.width ||
 	    sc->gc_height != sc->memregs.height) {
 		bhyvegc_resize(gc, sc->memregs.width, sc->memregs.height);
 		sc->gc_width = sc->memregs.width;
 		sc->gc_height = sc->memregs.height;
 	}
 
 	return;
 }
 
 static int
 pci_fbuf_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
 {
 	int error, prot;
 	struct pci_fbuf_softc *sc;
 	
 	if (fbuf_sc != NULL) {
 		fprintf(stderr, "Only one frame buffer device is allowed.\n");
 		return (-1);
 	}
 
 	sc = calloc(1, sizeof(struct pci_fbuf_softc));
 
 	pi->pi_arg = sc;
 
 	/* initialize config space */
 	pci_set_cfgdata16(pi, PCIR_DEVICE, 0x40FB);
 	pci_set_cfgdata16(pi, PCIR_VENDOR, 0xFB5D);
 	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_DISPLAY);
 	pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_DISPLAY_VGA);
 
 	error = pci_emul_alloc_bar(pi, 0, PCIBAR_MEM32, DMEMSZ);
 	assert(error == 0);
 
 	error = pci_emul_alloc_bar(pi, 1, PCIBAR_MEM32, FB_SIZE);
 	assert(error == 0);
 
 	error = pci_emul_add_msicap(pi, PCI_FBUF_MSI_MSGS);
 	assert(error == 0);
 
 	sc->fbaddr = pi->pi_bar[1].addr;
 	sc->memregs.fbsize = FB_SIZE;
 	sc->memregs.width  = COLS_DEFAULT;
 	sc->memregs.height = ROWS_DEFAULT;
 	sc->memregs.depth  = 32;
 
 	sc->vga_enabled = 1;
 	sc->vga_full = 0;
 
 	sc->fsc_pi = pi;
 
 	error = pci_fbuf_parse_opts(sc, opts);
 	if (error != 0)
 		goto done;
 
 	/* XXX until VGA rendering is enabled */
 	if (sc->vga_full != 0) {
 		fprintf(stderr, "pci_fbuf: VGA rendering not enabled");
 		goto done;
 	}
 
 	sc->fb_base = vm_create_devmem(ctx, VM_FRAMEBUFFER, "framebuffer", FB_SIZE);
 	if (sc->fb_base == MAP_FAILED) {
 		error = -1;
 		goto done;
 	}
 	DPRINTF(DEBUG_INFO, ("fbuf frame buffer base: %p [sz %lu]\r\n",
 	        sc->fb_base, FB_SIZE));
 
 	/*
 	 * Map the framebuffer into the guest address space.
 	 * XXX This may fail if the BAR is different than a prior
 	 * run. In this case flag the error. This will be fixed
 	 * when a change_memseg api is available.
 	 */
 	prot = PROT_READ | PROT_WRITE;
 	if (vm_mmap_memseg(ctx, sc->fbaddr, VM_FRAMEBUFFER, 0, FB_SIZE, prot) != 0) {
 		fprintf(stderr, "pci_fbuf: mapseg failed - try deleting VM and restarting\n");
 		error = -1;
 		goto done;
 	}
 
 	console_init(sc->memregs.width, sc->memregs.height, sc->fb_base);
 	console_fb_register(pci_fbuf_render, sc);
 
 	if (sc->vga_enabled)
 		sc->vgasc = vga_init(!sc->vga_full);
 	sc->gc_image = console_get_image();
 
 	fbuf_sc = sc;
 
 	memset((void *)sc->fb_base, 0, FB_SIZE);
 
-	error = rfb_init(sc->rfb_host, sc->rfb_port, sc->rfb_wait);
+	error = rfb_init(sc->rfb_host, sc->rfb_port, sc->rfb_wait, sc->rfb_password);
 done:
 	if (error)
 		free(sc);
 
 	return (error);
 }
 
 struct pci_devemu pci_fbuf = {
 	.pe_emu =	"fbuf",
 	.pe_init =	pci_fbuf_init,
 	.pe_barwrite =	pci_fbuf_write,
 	.pe_barread =	pci_fbuf_read
 };
 PCI_EMUL_SET(pci_fbuf);
Index: head/usr.sbin/bhyve/rfb.c
===================================================================
--- head/usr.sbin/bhyve/rfb.c	(revision 319486)
+++ head/usr.sbin/bhyve/rfb.c	(revision 319487)
@@ -1,941 +1,1041 @@
 /*-
  * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
  * Copyright (c) 2015 Leon Dang
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #ifndef WITHOUT_CAPSICUM
 #include <sys/capsicum.h>
 #endif
 #include <sys/socket.h>
 #include <sys/select.h>
 #include <sys/time.h>
 #include <arpa/inet.h>
 #include <machine/cpufunc.h>
 #include <machine/specialreg.h>
 #include <netinet/in.h>
 
 #include <assert.h>
 #include <err.h>
 #include <errno.h>
 #include <pthread.h>
 #include <pthread_np.h>
 #include <signal.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <sysexits.h>
 #include <unistd.h>
 
 #include <zlib.h>
 
 #include "bhyvegc.h"
 #include "console.h"
 #include "rfb.h"
 #include "sockstream.h"
 
+#ifndef NO_OPENSSL
+#include <openssl/des.h>
+#endif
+
 static int rfb_debug = 0;
 #define	DPRINTF(params) if (rfb_debug) printf params
 #define	WPRINTF(params) printf params
 
+#define AUTH_LENGTH	16
+#define PASSWD_LENGTH	8
+
+#define SECURITY_TYPE_NONE 1
+#define SECURITY_TYPE_VNC_AUTH 2
+
+#define AUTH_FAILED_UNAUTH 1
+#define AUTH_FAILED_ERROR 2
+
 struct rfb_softc {
 	int		sfd;
 	pthread_t	tid;
 
 	int		cfd;
 
 	int		width, height;
 
-	bool		enc_raw_ok;
-	bool		enc_zlib_ok;
-	bool		enc_resize_ok;
+	char		*password;
 
+	bool	enc_raw_ok;
+	bool	enc_zlib_ok;
+	bool	enc_resize_ok;
+
 	z_stream	zstream;
 	uint8_t		*zbuf;
 	int		zbuflen;
 
 	int		conn_wait;
 	int		sending;
 	pthread_mutex_t mtx;
 	pthread_cond_t  cond;
 
 	int		hw_crc;
 	uint32_t	*crc;		/* WxH crc cells */
 	uint32_t	*crc_tmp;	/* buffer to store single crc row */
 	int		crc_width, crc_height;
 };
 
 struct rfb_pixfmt {
 	uint8_t		bpp;
 	uint8_t		depth;
 	uint8_t		bigendian;
 	uint8_t		truecolor;
 	uint16_t	red_max;
 	uint16_t	green_max;
 	uint16_t	blue_max;
 	uint8_t		red_shift;
 	uint8_t		green_shift;
 	uint8_t		blue_shift;
 	uint8_t		pad[3];
 };
 
 struct rfb_srvr_info {
 	uint16_t		width;
 	uint16_t		height;
 	struct rfb_pixfmt	pixfmt;
 	uint32_t		namelen;
 };
 
 struct rfb_pixfmt_msg {
 	uint8_t			type;
 	uint8_t			pad[3];
 	struct rfb_pixfmt	pixfmt;
 };
 
 #define	RFB_ENCODING_RAW		0
 #define	RFB_ENCODING_ZLIB		6
 #define	RFB_ENCODING_RESIZE		-223
 
 #define RFB_MAX_WIDTH			2000
 #define RFB_MAX_HEIGHT			1200
 #define	RFB_ZLIB_BUFSZ			RFB_MAX_WIDTH*RFB_MAX_HEIGHT*4
 
 /* percentage changes to screen before sending the entire screen */
 #define RFB_SEND_ALL_THRESH             25
 
 struct rfb_enc_msg {
 	uint8_t		type;
 	uint8_t		pad;
 	uint16_t	numencs;
 };
 
 struct rfb_updt_msg {
 	uint8_t		type;
 	uint8_t		incremental;
 	uint16_t	x;
 	uint16_t	y;
 	uint16_t	width;
 	uint16_t	height;
 };
 
 struct rfb_key_msg {
 	uint8_t		type;
 	uint8_t		down;
 	uint16_t	pad;
 	uint32_t	code;
 };
 
 struct rfb_ptr_msg {
 	uint8_t		type;
 	uint8_t		button;
 	uint16_t	x;
 	uint16_t	y;
 };
 
 struct rfb_srvr_updt_msg {
 	uint8_t		type;
 	uint8_t		pad;
 	uint16_t	numrects;
 };
 
 struct rfb_srvr_rect_hdr {
 	uint16_t	x;
 	uint16_t	y;
 	uint16_t	width;
 	uint16_t	height;
 	uint32_t	encoding;
 };
 
 struct rfb_cuttext_msg {
 	uint8_t		type;
 	uint8_t		padding[3];
 	uint32_t	length;
 };
 
 
 static void
 rfb_send_server_init_msg(int cfd)
 {
 	struct bhyvegc_image *gc_image;
 	struct rfb_srvr_info sinfo;
 
 	gc_image = console_get_image();
 
 	sinfo.width = htons(gc_image->width);
 	sinfo.height = htons(gc_image->height);
 	sinfo.pixfmt.bpp = 32;
 	sinfo.pixfmt.depth = 32;
 	sinfo.pixfmt.bigendian = 0;
 	sinfo.pixfmt.truecolor = 1;
 	sinfo.pixfmt.red_max = htons(255);
 	sinfo.pixfmt.green_max = htons(255);
 	sinfo.pixfmt.blue_max = htons(255);
 	sinfo.pixfmt.red_shift = 16;
 	sinfo.pixfmt.green_shift = 8;
 	sinfo.pixfmt.blue_shift = 0;
 	sinfo.namelen = htonl(strlen("bhyve"));
 	(void)stream_write(cfd, &sinfo, sizeof(sinfo));
 	(void)stream_write(cfd, "bhyve", strlen("bhyve"));
 }
 
 static void
 rfb_send_resize_update_msg(struct rfb_softc *rc, int cfd)
 {
 	struct rfb_srvr_updt_msg supdt_msg;
-        struct rfb_srvr_rect_hdr srect_hdr;
+	struct rfb_srvr_rect_hdr srect_hdr;
 
 	/* Number of rectangles: 1 */
 	supdt_msg.type = 0;
 	supdt_msg.pad = 0;
 	supdt_msg.numrects = htons(1);
 	stream_write(cfd, &supdt_msg, sizeof(struct rfb_srvr_updt_msg));
 
 	/* Rectangle header */
 	srect_hdr.x = htons(0);
 	srect_hdr.y = htons(0);
 	srect_hdr.width = htons(rc->width);
 	srect_hdr.height = htons(rc->height);
 	srect_hdr.encoding = htonl(RFB_ENCODING_RESIZE);
 	stream_write(cfd, &srect_hdr, sizeof(struct rfb_srvr_rect_hdr));
 }
 
 static void
 rfb_recv_set_pixfmt_msg(struct rfb_softc *rc, int cfd)
 {
 	struct rfb_pixfmt_msg pixfmt_msg;
 
 	(void)stream_read(cfd, ((void *)&pixfmt_msg)+1, sizeof(pixfmt_msg)-1);
 }
 
 
 static void
 rfb_recv_set_encodings_msg(struct rfb_softc *rc, int cfd)
 {
 	struct rfb_enc_msg enc_msg;
 	int i;
 	uint32_t encoding;
 
 	assert((sizeof(enc_msg) - 1) == 3);
 	(void)stream_read(cfd, ((void *)&enc_msg)+1, sizeof(enc_msg)-1);
 
 	for (i = 0; i < htons(enc_msg.numencs); i++) {
 		(void)stream_read(cfd, &encoding, sizeof(encoding));
 		switch (htonl(encoding)) {
 		case RFB_ENCODING_RAW:
 			rc->enc_raw_ok = true;
 			break;
 		case RFB_ENCODING_ZLIB:
 			rc->enc_zlib_ok = true;
 			deflateInit(&rc->zstream, Z_BEST_SPEED);
 			break;
 		case RFB_ENCODING_RESIZE:
 			rc->enc_resize_ok = true;
 			break;
 		}
 	}
 }
 
 /*
  * Calculate CRC32 using SSE4.2; Intel or AMD Bulldozer+ CPUs only
  */
 static __inline uint32_t
 fast_crc32(void *buf, int len, uint32_t crcval)
 {
 	uint32_t q = len / sizeof(uint32_t);
 	uint32_t *p = (uint32_t *)buf;
 
 	while (q--) {
 		asm volatile (
 			".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
 			:"=S" (crcval)
 			:"0" (crcval), "c" (*p)
 		);
 		p++;
 	}
 
 	return (crcval);
 }
 
 
 static int
 rfb_send_rect(struct rfb_softc *rc, int cfd, struct bhyvegc_image *gc,
               int x, int y, int w, int h)
 {
 	struct rfb_srvr_updt_msg supdt_msg;
         struct rfb_srvr_rect_hdr srect_hdr;
 	unsigned long zlen;
 	ssize_t nwrite, total;
 	int err;
 	uint32_t *p;
 	uint8_t *zbufp;
 
 	/*
 	 * Send a single rectangle of the given x, y, w h dimensions.
 	 */
 
 	/* Number of rectangles: 1 */
 	supdt_msg.type = 0;
 	supdt_msg.pad = 0;
 	supdt_msg.numrects = htons(1);
 	nwrite = stream_write(cfd, &supdt_msg,
 	                      sizeof(struct rfb_srvr_updt_msg));
 	if (nwrite <= 0)
 		return (nwrite);
 
 
 	/* Rectangle header */
 	srect_hdr.x = htons(x);
 	srect_hdr.y = htons(y);
 	srect_hdr.width = htons(w);
 	srect_hdr.height = htons(h);
 
 	h = y + h;
 	w *= sizeof(uint32_t);
 	if (rc->enc_zlib_ok) {
 		zbufp = rc->zbuf;
 		rc->zstream.total_in = 0;
 		rc->zstream.total_out = 0;
 		for (p = &gc->data[y * gc->width + x]; y < h; y++) {
 			rc->zstream.next_in = (Bytef *)p;
 			rc->zstream.avail_in = w;
 			rc->zstream.next_out = (Bytef *)zbufp;
 			rc->zstream.avail_out = RFB_ZLIB_BUFSZ + 16 -
 			                        rc->zstream.total_out;
 			rc->zstream.data_type = Z_BINARY;
 
 			/* Compress with zlib */
 			err = deflate(&rc->zstream, Z_SYNC_FLUSH);
 			if (err != Z_OK) {
 				WPRINTF(("zlib[rect] deflate err: %d\n", err));
 				rc->enc_zlib_ok = false;
 				deflateEnd(&rc->zstream);
 				goto doraw;
 			}
 			zbufp = rc->zbuf + rc->zstream.total_out;
 			p += gc->width;
 		}
 		srect_hdr.encoding = htonl(RFB_ENCODING_ZLIB);
 		nwrite = stream_write(cfd, &srect_hdr,
 		                      sizeof(struct rfb_srvr_rect_hdr));
 		if (nwrite <= 0)
 			return (nwrite);
 
 		zlen = htonl(rc->zstream.total_out);
 		nwrite = stream_write(cfd, &zlen, sizeof(uint32_t));
 		if (nwrite <= 0)
 			return (nwrite);
 		return (stream_write(cfd, rc->zbuf, rc->zstream.total_out));
 	}
 
 doraw:
 
 	total = 0;
 	zbufp = rc->zbuf;
 	for (p = &gc->data[y * gc->width + x]; y < h; y++) {
 		memcpy(zbufp, p, w);
 		zbufp += w;
 		total += w;
 		p += gc->width;
 	}
 
 	srect_hdr.encoding = htonl(RFB_ENCODING_RAW);
 	nwrite = stream_write(cfd, &srect_hdr,
 	                      sizeof(struct rfb_srvr_rect_hdr));
 	if (nwrite <= 0)
 		return (nwrite);
 
 	total = stream_write(cfd, rc->zbuf, total);
 
 	return (total);
 }
 
 static int
 rfb_send_all(struct rfb_softc *rc, int cfd, struct bhyvegc_image *gc)
 {
 	struct rfb_srvr_updt_msg supdt_msg;
         struct rfb_srvr_rect_hdr srect_hdr;
 	ssize_t nwrite;
 	unsigned long zlen;
 	int err;
 
 	/*
 	 * Send the whole thing
 	 */
 
 	/* Number of rectangles: 1 */
 	supdt_msg.type = 0;
 	supdt_msg.pad = 0;
 	supdt_msg.numrects = htons(1);
 	nwrite = stream_write(cfd, &supdt_msg,
 	                      sizeof(struct rfb_srvr_updt_msg));
 	if (nwrite <= 0)
 		return (nwrite);
 
 	/* Rectangle header */
 	srect_hdr.x = 0;
 	srect_hdr.y = 0;
 	srect_hdr.width = htons(gc->width);
 	srect_hdr.height = htons(gc->height);
 	if (rc->enc_zlib_ok) {
 		rc->zstream.next_in = (Bytef *)gc->data;
 		rc->zstream.avail_in = gc->width * gc->height *
 		                   sizeof(uint32_t);
 		rc->zstream.next_out = (Bytef *)rc->zbuf;
 		rc->zstream.avail_out = RFB_ZLIB_BUFSZ + 16;
 		rc->zstream.data_type = Z_BINARY;
 
 		rc->zstream.total_in = 0;
 		rc->zstream.total_out = 0;
 
 		/* Compress with zlib */
 		err = deflate(&rc->zstream, Z_SYNC_FLUSH);
 		if (err != Z_OK) {
 			WPRINTF(("zlib deflate err: %d\n", err));
 			rc->enc_zlib_ok = false;
 			deflateEnd(&rc->zstream);
 			goto doraw;
 		}
 
 		srect_hdr.encoding = htonl(RFB_ENCODING_ZLIB);
 		nwrite = stream_write(cfd, &srect_hdr,
 		                      sizeof(struct rfb_srvr_rect_hdr));
 		if (nwrite <= 0)
 			return (nwrite);
 
 		zlen = htonl(rc->zstream.total_out);
 		nwrite = stream_write(cfd, &zlen, sizeof(uint32_t));
 		if (nwrite <= 0)
 			return (nwrite);
 		return (stream_write(cfd, rc->zbuf, rc->zstream.total_out));
 	}
 
 doraw:
 	srect_hdr.encoding = htonl(RFB_ENCODING_RAW);
 	nwrite = stream_write(cfd, &srect_hdr,
 	                      sizeof(struct rfb_srvr_rect_hdr));
 	if (nwrite <= 0)
 		return (nwrite);
 
 	nwrite = stream_write(cfd, gc->data,
 	               gc->width * gc->height * sizeof(uint32_t));
 
 	return (nwrite);
 }
 
 #define PIX_PER_CELL	32
 #define	PIXCELL_SHIFT	5
 #define PIXCELL_MASK	0x1F
 
 static int
 rfb_send_screen(struct rfb_softc *rc, int cfd, int all)
 {
 	struct bhyvegc_image *gc_image;
 	ssize_t nwrite;
 	int x, y;
 	int celly, cellwidth;
 	int xcells, ycells;
 	int w, h;
 	uint32_t *p;
 	int rem_x, rem_y;   /* remainder for resolutions not x32 pixels ratio */
 	int retval;
 	uint32_t *crc_p, *orig_crc;
 	int changes;
 
 	console_refresh();
 	gc_image = console_get_image();
 
 	pthread_mutex_lock(&rc->mtx);
 	if (rc->sending) {
 		pthread_mutex_unlock(&rc->mtx);
 		return (1);
 	}
 	rc->sending = 1;
 	pthread_mutex_unlock(&rc->mtx);
 
 	retval = 0;
 
 	if (all) {
 		retval = rfb_send_all(rc, cfd, gc_image);
 		goto done;
 	}
 
 	/*
 	 * Calculate the checksum for each 32x32 cell. Send each that
 	 * has changed since the last scan.
 	 */
 
 	/* Resolution changed */
 
 	rc->crc_width = gc_image->width;
 	rc->crc_height = gc_image->height;
 
 	w = rc->crc_width;
 	h = rc->crc_height;
 	xcells = howmany(rc->crc_width, PIX_PER_CELL);
 	ycells = howmany(rc->crc_height, PIX_PER_CELL);
 
 	rem_x = w & PIXCELL_MASK;
 
 	rem_y = h & PIXCELL_MASK;
 	if (!rem_y)
 		rem_y = PIX_PER_CELL;
 
 	p = gc_image->data;
 
 	/*
 	 * Go through all cells and calculate crc. If significant number
 	 * of changes, then send entire screen.
 	 * crc_tmp is dual purpose: to store the new crc and to flag as
 	 * a cell that has changed.
 	 */
 	crc_p = rc->crc_tmp - xcells;
 	orig_crc = rc->crc - xcells;
 	changes = 0;
 	memset(rc->crc_tmp, 0, sizeof(uint32_t) * xcells * ycells);
 	for (y = 0; y < h; y++) {
 		if ((y & PIXCELL_MASK) == 0) {
 			crc_p += xcells;
 			orig_crc += xcells;
 		}
 
 		for (x = 0; x < xcells; x++) {
 			if (rc->hw_crc)
 				crc_p[x] = fast_crc32(p,
 				             PIX_PER_CELL * sizeof(uint32_t),
 				             crc_p[x]);
 			else
 				crc_p[x] = (uint32_t)crc32(crc_p[x],
 				             (Bytef *)p,
 				             PIX_PER_CELL * sizeof(uint32_t));
 
 			p += PIX_PER_CELL;
 
 			/* check for crc delta if last row in cell */
 			if ((y & PIXCELL_MASK) == PIXCELL_MASK || y == (h-1)) {
 				if (orig_crc[x] != crc_p[x]) {
 					orig_crc[x] = crc_p[x];
 					crc_p[x] = 1;
 					changes++;
 				} else {
 					crc_p[x] = 0;
 				}
 			}
 		}
 
 		if (rem_x) {
 			if (rc->hw_crc)
 				crc_p[x] = fast_crc32(p,
 				                    rem_x * sizeof(uint32_t),
 				                    crc_p[x]);
 			else
 				crc_p[x] = (uint32_t)crc32(crc_p[x],
 				                    (Bytef *)p,
 				                    rem_x * sizeof(uint32_t));
 			p += rem_x;
 
 			if ((y & PIXCELL_MASK) == PIXCELL_MASK || y == (h-1)) {
 				if (orig_crc[x] != crc_p[x]) {
 					orig_crc[x] = crc_p[x];
 					crc_p[x] = 1;
 					changes++;
 				} else {
 					crc_p[x] = 0;
 				}
 			}
 		}
 	}
 
 	/* If number of changes is > THRESH percent, send the whole screen */
 	if (((changes * 100) / (xcells * ycells)) >= RFB_SEND_ALL_THRESH) {
 		retval = rfb_send_all(rc, cfd, gc_image);
 		goto done;
 	}
 	
 	/* Go through all cells, and send only changed ones */
 	crc_p = rc->crc_tmp;
 	for (y = 0; y < h; y += PIX_PER_CELL) {
 		/* previous cell's row */
 		celly = (y >> PIXCELL_SHIFT);
 
 		/* Delta check crc to previous set */
 		for (x = 0; x < xcells; x++) {
 			if (*crc_p++ == 0)
 				continue;
 
 			if (x == (xcells - 1) && rem_x > 0)
 				cellwidth = rem_x;
 			else
 				cellwidth = PIX_PER_CELL;
 			nwrite = rfb_send_rect(rc, cfd,
 				gc_image,
 				x * PIX_PER_CELL,
 				celly * PIX_PER_CELL,
 			        cellwidth,
 				y + PIX_PER_CELL >= h ? rem_y : PIX_PER_CELL);
 			if (nwrite <= 0) {
 				retval = nwrite;
 				goto done;
 			}
 		}
 	}
 	retval = 1;
 
 done:
 	pthread_mutex_lock(&rc->mtx);
 	rc->sending = 0;
 	pthread_mutex_unlock(&rc->mtx);
 	
 	return (retval);
 }
 
 
 static void
 rfb_recv_update_msg(struct rfb_softc *rc, int cfd, int discardonly)
 {
 	struct rfb_updt_msg updt_msg;
 	struct bhyvegc_image *gc_image;
 
 	(void)stream_read(cfd, ((void *)&updt_msg) + 1 , sizeof(updt_msg) - 1);
 
 	console_refresh();
 	gc_image = console_get_image();
 
 	updt_msg.x = htons(updt_msg.x);
 	updt_msg.y = htons(updt_msg.y);
 	updt_msg.width = htons(updt_msg.width);
 	updt_msg.height = htons(updt_msg.height);
 
 	if (updt_msg.width != gc_image->width ||
 	    updt_msg.height != gc_image->height) {
 		rc->width = gc_image->width;
 		rc->height = gc_image->height;
 		if (rc->enc_resize_ok)
 			rfb_send_resize_update_msg(rc, cfd);
 	}
 
 	if (discardonly)
 		return;
 
 	rfb_send_screen(rc, cfd, 1);
 }
 
 static void
 rfb_recv_key_msg(struct rfb_softc *rc, int cfd)
 {
 	struct rfb_key_msg key_msg;
 
 	(void)stream_read(cfd, ((void *)&key_msg) + 1, sizeof(key_msg) - 1);
 
 	console_key_event(key_msg.down, htonl(key_msg.code));
 }
 
 static void
 rfb_recv_ptr_msg(struct rfb_softc *rc, int cfd)
 {
 	struct rfb_ptr_msg ptr_msg;
 
 	(void)stream_read(cfd, ((void *)&ptr_msg) + 1, sizeof(ptr_msg) - 1);
 
 	console_ptr_event(ptr_msg.button, htons(ptr_msg.x), htons(ptr_msg.y));
 }
 
 static void
 rfb_recv_cuttext_msg(struct rfb_softc *rc, int cfd)
 {
 	struct rfb_cuttext_msg ct_msg;
 	unsigned char buf[32];
 	int len;
 
 	len = stream_read(cfd, ((void *)&ct_msg) + 1, sizeof(ct_msg) - 1);
 	ct_msg.length = htonl(ct_msg.length);
 	while (ct_msg.length > 0) {
 		len = stream_read(cfd, buf, ct_msg.length > sizeof(buf) ?
 			sizeof(buf) : ct_msg.length);
 		ct_msg.length -= len;
 	}
 }
 
 static int64_t
 timeval_delta(struct timeval *prev, struct timeval *now)
 {
 	int64_t n1, n2;
 	n1 = now->tv_sec * 1000000 + now->tv_usec;
 	n2 = prev->tv_sec * 1000000 + prev->tv_usec;
 	return (n1 - n2);
 }
 
 static void *
 rfb_wr_thr(void *arg)
 {
 	struct rfb_softc *rc;
 	fd_set rfds;
 	struct timeval tv;
 	struct timeval prev_tv;
 	int64_t tdiff;
 	int cfd;
 	int err;
 
 	rc = arg;
 	cfd = rc->cfd;
 
 	prev_tv.tv_sec = 0;
 	prev_tv.tv_usec = 0;
 	while (rc->cfd >= 0) {
 		FD_ZERO(&rfds);
 		FD_SET(cfd, &rfds);
 		tv.tv_sec = 0;
 		tv.tv_usec = 10000;
 
 		err = select(cfd+1, &rfds, NULL, NULL, &tv);
                 if (err < 0)
 			return (NULL);
 
 		/* Determine if its time to push screen; ~24hz */
 		gettimeofday(&tv, NULL);
 		tdiff = timeval_delta(&prev_tv, &tv);
 		if (tdiff > 40000) {
 			prev_tv.tv_sec = tv.tv_sec;
 			prev_tv.tv_usec = tv.tv_usec;
 			if (rfb_send_screen(rc, cfd, 0) <= 0) {
 				return (NULL);
 			}
 		} else {
 			/* sleep */
 			usleep(40000 - tdiff);
 		}
 	}
 
 	return (NULL);
 }
 
 void
 rfb_handle(struct rfb_softc *rc, int cfd)
 {
 	const char *vbuf = "RFB 003.008\n";
 	unsigned char buf[80];
+	unsigned char *message;
+
+#ifndef NO_OPENSSL
+	unsigned char challenge[AUTH_LENGTH];
+	unsigned char keystr[PASSWD_LENGTH];
+	unsigned char crypt_expected[AUTH_LENGTH];
+
+	DES_key_schedule ks;
+	int i;
+#endif
+
 	pthread_t tid;
-        uint32_t sres;
+	uint32_t sres;
 	int len;
 
 	rc->cfd = cfd;
 
 	/* 1a. Send server version */
 	stream_write(cfd, vbuf, strlen(vbuf));
 
 	/* 1b. Read client version */
 	len = read(cfd, buf, sizeof(buf));
 
-	/* 2a. Send security type 'none' */
+	/* 2a. Send security type */
 	buf[0] = 1;
-	buf[1] = 1; /* none */
+#ifndef NO_OPENSSL
+	if (rc->password) 
+		buf[1] = SECURITY_TYPE_VNC_AUTH;
+	else
+		buf[1] = SECURITY_TYPE_NONE;
+#else
+	buf[1] = SECURITY_TYPE_NONE;
+#endif
+
 	stream_write(cfd, buf, 2);
 
-
 	/* 2b. Read agreed security type */
 	len = stream_read(cfd, buf, 1);
 
-	/* 2c. Write back a status of 0 */
-	sres = 0;
+	/* 2c. Do VNC authentication */
+	switch (buf[0]) {
+	case SECURITY_TYPE_NONE:
+		sres = 0;
+		break;
+	case SECURITY_TYPE_VNC_AUTH:
+		/*
+		 * The client encrypts the challenge with DES, using a password
+		 * supplied by the user as the key.
+		 * To form the key, the password is truncated to
+		 * eight characters, or padded with null bytes on the right.
+		 * The client then sends the resulting 16-bytes response.
+		 */
+#ifndef NO_OPENSSL
+		strncpy(keystr, rc->password, PASSWD_LENGTH);
+
+		/* VNC clients encrypts the challenge with all the bit fields
+		 * in each byte of the password mirrored.
+		 * Here we flip each byte of the keystr.
+		 */
+		for (i = 0; i < PASSWD_LENGTH; i++) {
+			keystr[i] = (keystr[i] & 0xF0) >> 4
+				  | (keystr[i] & 0x0F) << 4;
+			keystr[i] = (keystr[i] & 0xCC) >> 2
+				  | (keystr[i] & 0x33) << 2;
+			keystr[i] = (keystr[i] & 0xAA) >> 1
+				  | (keystr[i] & 0x55) << 1;
+		}
+
+		/* Initialize a 16-byte random challenge */
+		arc4random_buf(challenge, sizeof(challenge));
+		stream_write(cfd, challenge, AUTH_LENGTH);
+
+		/* Receive the 16-byte challenge response */
+		stream_read(cfd, buf, AUTH_LENGTH);
+
+		memcpy(crypt_expected, challenge, AUTH_LENGTH);
+
+		/* Encrypt the Challenge with DES */
+		DES_set_key((C_Block *)keystr, &ks);
+		DES_ecb_encrypt((C_Block *)challenge,
+				(C_Block *)crypt_expected, &ks, DES_ENCRYPT);
+		DES_ecb_encrypt((C_Block *)(challenge + PASSWD_LENGTH),
+				(C_Block *)(crypt_expected + PASSWD_LENGTH),
+				&ks, DES_ENCRYPT);
+
+		if (memcmp(crypt_expected, buf, AUTH_LENGTH) != 0) {
+			message = "Auth Failed: Invalid Password.";
+			sres = htonl(1);
+		} else
+			sres = 0;
+#else
+		sres = 0;
+		WPRINTF(("Auth not supported, no OpenSSL in your system"));
+#endif
+
+		break;
+	}
+
+	/* 2d. Write back a status */
 	stream_write(cfd, &sres, 4);
 
+	if (sres) {
+		*((uint32_t *) buf) = htonl(strlen(message));
+		stream_write(cfd, buf, 4);
+                stream_write(cfd, message, strlen(message));
+		goto done;
+	}
+
 	/* 3a. Read client shared-flag byte */
 	len = stream_read(cfd, buf, 1);
 
 	/* 4a. Write server-init info */
 	rfb_send_server_init_msg(cfd);
 
 	if (!rc->zbuf) {
 		rc->zbuf = malloc(RFB_ZLIB_BUFSZ + 16);
 		assert(rc->zbuf != NULL);
 	}
 
 	rfb_send_screen(rc, cfd, 1);
 
 	pthread_create(&tid, NULL, rfb_wr_thr, rc);
 	pthread_set_name_np(tid, "rfbout");
 
         /* Now read in client requests. 1st byte identifies type */
 	for (;;) {
 		len = read(cfd, buf, 1);
 		if (len <= 0) {
 			DPRINTF(("rfb client exiting\r\n"));
 			break;
 		}
 
 		switch (buf[0]) {
 		case 0:
 			rfb_recv_set_pixfmt_msg(rc, cfd);
 			break;
 		case 2:
 			rfb_recv_set_encodings_msg(rc, cfd);
 			break;
 		case 3:
 			rfb_recv_update_msg(rc, cfd, 1);
 			break;
 		case 4:
 			rfb_recv_key_msg(rc, cfd);
 			break;
 		case 5:
 			rfb_recv_ptr_msg(rc, cfd);
 			break;
 		case 6:
 			rfb_recv_cuttext_msg(rc, cfd);
 			break;
 		default:
 			WPRINTF(("rfb unknown cli-code %d!\n", buf[0] & 0xff));
 			goto done;
 		}
 	}
 done:
 	rc->cfd = -1;
 	pthread_join(tid, NULL);
 	if (rc->enc_zlib_ok)
 		deflateEnd(&rc->zstream);
 }
 
 static void *
 rfb_thr(void *arg)
 {
 	struct rfb_softc *rc;
 	sigset_t set;
 
 	int cfd;
 
 	rc = arg;
 
 	sigemptyset(&set);
 	sigaddset(&set, SIGPIPE);
 	if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) {
 		perror("pthread_sigmask");
 		return (NULL);
 	}
 
 	for (;;) {
 		rc->enc_raw_ok = false;
 		rc->enc_zlib_ok = false;
 		rc->enc_resize_ok = false;
 
 		cfd = accept(rc->sfd, NULL, NULL);
 		if (rc->conn_wait) {
 			pthread_mutex_lock(&rc->mtx);
 			pthread_cond_signal(&rc->cond);
 			pthread_mutex_unlock(&rc->mtx);
 			rc->conn_wait = 0;
 		}
 		rfb_handle(rc, cfd);
 		close(cfd);
 	}
 
 	/* NOTREACHED */
 	return (NULL);
 }
 
 static int
 sse42_supported(void)
 {
 	u_int cpu_registers[4], ecx;
 
 	do_cpuid(1, cpu_registers);
 
 	ecx = cpu_registers[2];
 
 	return ((ecx & CPUID2_SSE42) != 0);
 }
 
 int
-rfb_init(char *hostname, int port, int wait)
+rfb_init(char *hostname, int port, int wait, char *password)
 {
 	struct rfb_softc *rc;
 	struct sockaddr_in sin;
 	int on = 1;
 #ifndef WITHOUT_CAPSICUM
 	cap_rights_t rights;
 #endif
 
 	rc = calloc(1, sizeof(struct rfb_softc));
 
 	rc->crc = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32),
 	                 sizeof(uint32_t));
 	rc->crc_tmp = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32),
 	                     sizeof(uint32_t));
 	rc->crc_width = RFB_MAX_WIDTH;
 	rc->crc_height = RFB_MAX_HEIGHT;
+
+	rc->password = password;
 
 	rc->sfd = socket(AF_INET, SOCK_STREAM, 0);
 	if (rc->sfd < 0) {
 		perror("socket");
 		return (-1);
 	}
 
 	setsockopt(rc->sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
 
 	sin.sin_len = sizeof(sin);
 	sin.sin_family = AF_INET;
 	sin.sin_port = port ? htons(port) : htons(5900);
 	if (hostname && strlen(hostname) > 0)
 		inet_pton(AF_INET, hostname, &(sin.sin_addr));
 	else
 		sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 
 	if (bind(rc->sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
 		perror("bind");
 		return (-1);
 	}
 
 	if (listen(rc->sfd, 1) < 0) {
 		perror("listen");
 		return (-1);
 	}
 
 #ifndef WITHOUT_CAPSICUM
 	cap_rights_init(&rights, CAP_ACCEPT, CAP_EVENT, CAP_READ, CAP_WRITE);
 	if (cap_rights_limit(rc->sfd, &rights) == -1 && errno != ENOSYS)
 		errx(EX_OSERR, "Unable to apply rights for sandbox");
 #endif
 
 	rc->hw_crc = sse42_supported();
 
 	rc->conn_wait = wait;
 	if (wait) {
 		pthread_mutex_init(&rc->mtx, NULL);
 		pthread_cond_init(&rc->cond, NULL);
 	}
 
 	pthread_create(&rc->tid, NULL, rfb_thr, rc);
 	pthread_set_name_np(rc->tid, "rfb");
 
 	if (wait) {
 		DPRINTF(("Waiting for rfb client...\n"));
 		pthread_mutex_lock(&rc->mtx);
 		pthread_cond_wait(&rc->cond, &rc->mtx);
 		pthread_mutex_unlock(&rc->mtx);
 	}
 
 	return (0);
 }
Index: head/usr.sbin/bhyve/rfb.h
===================================================================
--- head/usr.sbin/bhyve/rfb.h	(revision 319486)
+++ head/usr.sbin/bhyve/rfb.h	(revision 319487)
@@ -1,36 +1,36 @@
 /*-
  * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * $FreeBSD$
  */
 
 #ifndef _RFB_H_
 #define	_RFB_H_
 
 #define	RFB_PORT	5900
 
-int	rfb_init(char *hostname, int port, int wait);
+int	rfb_init(char *hostname, int port, int wait, char *password);
 
 #endif /* _RFB_H_ */