rfb.c revision 349435
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
5 * Copyright (c) 2015 Leon Dang
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: stable/11/usr.sbin/bhyve/rfb.c 349435 2019-06-26 17:42:47Z markj $");
32
33#include <sys/param.h>
34#include <sys/endian.h>
35#ifndef WITHOUT_CAPSICUM
36#include <sys/capsicum.h>
37#endif
38#include <sys/socket.h>
39#include <sys/select.h>
40#include <sys/time.h>
41#include <arpa/inet.h>
42#include <machine/cpufunc.h>
43#include <machine/specialreg.h>
44#include <netinet/in.h>
45#include <netdb.h>
46
47#include <assert.h>
48#include <err.h>
49#include <errno.h>
50#include <pthread.h>
51#include <pthread_np.h>
52#include <signal.h>
53#include <stdbool.h>
54#include <stdlib.h>
55#include <stdio.h>
56#include <string.h>
57#include <sysexits.h>
58#include <unistd.h>
59
60#include <zlib.h>
61
62#include "bhyvegc.h"
63#include "console.h"
64#include "rfb.h"
65#include "sockstream.h"
66
67#ifndef NO_OPENSSL
68#include <openssl/des.h>
69#endif
70
71static int rfb_debug = 0;
72#define	DPRINTF(params) if (rfb_debug) printf params
73#define	WPRINTF(params) printf params
74
75#define AUTH_LENGTH	16
76#define PASSWD_LENGTH	8
77
78#define SECURITY_TYPE_NONE	1
79#define SECURITY_TYPE_VNC_AUTH	2
80
81#define AUTH_FAILED_UNAUTH	1
82#define AUTH_FAILED_ERROR	2
83
84struct rfb_softc {
85	int		sfd;
86	pthread_t	tid;
87
88	int		cfd;
89
90	int		width, height;
91
92	char		*password;
93
94	bool	enc_raw_ok;
95	bool	enc_zlib_ok;
96	bool	enc_resize_ok;
97
98	z_stream	zstream;
99	uint8_t		*zbuf;
100	int		zbuflen;
101
102	int		conn_wait;
103	int		sending;
104	pthread_mutex_t mtx;
105	pthread_cond_t  cond;
106
107	int		hw_crc;
108	uint32_t	*crc;		/* WxH crc cells */
109	uint32_t	*crc_tmp;	/* buffer to store single crc row */
110	int		crc_width, crc_height;
111};
112
113struct rfb_pixfmt {
114	uint8_t		bpp;
115	uint8_t		depth;
116	uint8_t		bigendian;
117	uint8_t		truecolor;
118	uint16_t	red_max;
119	uint16_t	green_max;
120	uint16_t	blue_max;
121	uint8_t		red_shift;
122	uint8_t		green_shift;
123	uint8_t		blue_shift;
124	uint8_t		pad[3];
125};
126
127struct rfb_srvr_info {
128	uint16_t		width;
129	uint16_t		height;
130	struct rfb_pixfmt	pixfmt;
131	uint32_t		namelen;
132};
133
134struct rfb_pixfmt_msg {
135	uint8_t			type;
136	uint8_t			pad[3];
137	struct rfb_pixfmt	pixfmt;
138};
139
140#define	RFB_ENCODING_RAW		0
141#define	RFB_ENCODING_ZLIB		6
142#define	RFB_ENCODING_RESIZE		-223
143
144#define	RFB_MAX_WIDTH			2000
145#define	RFB_MAX_HEIGHT			1200
146#define	RFB_ZLIB_BUFSZ			RFB_MAX_WIDTH*RFB_MAX_HEIGHT*4
147
148/* percentage changes to screen before sending the entire screen */
149#define	RFB_SEND_ALL_THRESH		25
150
151struct rfb_enc_msg {
152	uint8_t		type;
153	uint8_t		pad;
154	uint16_t	numencs;
155};
156
157struct rfb_updt_msg {
158	uint8_t		type;
159	uint8_t		incremental;
160	uint16_t	x;
161	uint16_t	y;
162	uint16_t	width;
163	uint16_t	height;
164};
165
166struct rfb_key_msg {
167	uint8_t		type;
168	uint8_t		down;
169	uint16_t	pad;
170	uint32_t	code;
171};
172
173struct rfb_ptr_msg {
174	uint8_t		type;
175	uint8_t		button;
176	uint16_t	x;
177	uint16_t	y;
178};
179
180struct rfb_srvr_updt_msg {
181	uint8_t		type;
182	uint8_t		pad;
183	uint16_t	numrects;
184};
185
186struct rfb_srvr_rect_hdr {
187	uint16_t	x;
188	uint16_t	y;
189	uint16_t	width;
190	uint16_t	height;
191	uint32_t	encoding;
192};
193
194struct rfb_cuttext_msg {
195	uint8_t		type;
196	uint8_t		padding[3];
197	uint32_t	length;
198};
199
200
201static void
202rfb_send_server_init_msg(int cfd)
203{
204	struct bhyvegc_image *gc_image;
205	struct rfb_srvr_info sinfo;
206
207	gc_image = console_get_image();
208
209	sinfo.width = htons(gc_image->width);
210	sinfo.height = htons(gc_image->height);
211	sinfo.pixfmt.bpp = 32;
212	sinfo.pixfmt.depth = 32;
213	sinfo.pixfmt.bigendian = 0;
214	sinfo.pixfmt.truecolor = 1;
215	sinfo.pixfmt.red_max = htons(255);
216	sinfo.pixfmt.green_max = htons(255);
217	sinfo.pixfmt.blue_max = htons(255);
218	sinfo.pixfmt.red_shift = 16;
219	sinfo.pixfmt.green_shift = 8;
220	sinfo.pixfmt.blue_shift = 0;
221	sinfo.namelen = htonl(strlen("bhyve"));
222	(void)stream_write(cfd, &sinfo, sizeof(sinfo));
223	(void)stream_write(cfd, "bhyve", strlen("bhyve"));
224}
225
226static void
227rfb_send_resize_update_msg(struct rfb_softc *rc, int cfd)
228{
229	struct rfb_srvr_updt_msg supdt_msg;
230	struct rfb_srvr_rect_hdr srect_hdr;
231
232	/* Number of rectangles: 1 */
233	supdt_msg.type = 0;
234	supdt_msg.pad = 0;
235	supdt_msg.numrects = htons(1);
236	stream_write(cfd, &supdt_msg, sizeof(struct rfb_srvr_updt_msg));
237
238	/* Rectangle header */
239	srect_hdr.x = htons(0);
240	srect_hdr.y = htons(0);
241	srect_hdr.width = htons(rc->width);
242	srect_hdr.height = htons(rc->height);
243	srect_hdr.encoding = htonl(RFB_ENCODING_RESIZE);
244	stream_write(cfd, &srect_hdr, sizeof(struct rfb_srvr_rect_hdr));
245}
246
247static void
248rfb_recv_set_pixfmt_msg(struct rfb_softc *rc, int cfd)
249{
250	struct rfb_pixfmt_msg pixfmt_msg;
251
252	(void)stream_read(cfd, ((void *)&pixfmt_msg)+1, sizeof(pixfmt_msg)-1);
253}
254
255
256static void
257rfb_recv_set_encodings_msg(struct rfb_softc *rc, int cfd)
258{
259	struct rfb_enc_msg enc_msg;
260	int i;
261	uint32_t encoding;
262
263	assert((sizeof(enc_msg) - 1) == 3);
264	(void)stream_read(cfd, ((void *)&enc_msg)+1, sizeof(enc_msg)-1);
265
266	for (i = 0; i < htons(enc_msg.numencs); i++) {
267		(void)stream_read(cfd, &encoding, sizeof(encoding));
268		switch (htonl(encoding)) {
269		case RFB_ENCODING_RAW:
270			rc->enc_raw_ok = true;
271			break;
272		case RFB_ENCODING_ZLIB:
273			if (!rc->enc_zlib_ok) {
274				deflateInit(&rc->zstream, Z_BEST_SPEED);
275				rc->enc_zlib_ok = true;
276			}
277			break;
278		case RFB_ENCODING_RESIZE:
279			rc->enc_resize_ok = true;
280			break;
281		}
282	}
283}
284
285/*
286 * Calculate CRC32 using SSE4.2; Intel or AMD Bulldozer+ CPUs only
287 */
288static __inline uint32_t
289fast_crc32(void *buf, int len, uint32_t crcval)
290{
291	uint32_t q = len / sizeof(uint32_t);
292	uint32_t *p = (uint32_t *)buf;
293
294	while (q--) {
295		asm volatile (
296			".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
297			:"=S" (crcval)
298			:"0" (crcval), "c" (*p)
299		);
300		p++;
301	}
302
303	return (crcval);
304}
305
306
307static int
308rfb_send_rect(struct rfb_softc *rc, int cfd, struct bhyvegc_image *gc,
309              int x, int y, int w, int h)
310{
311	struct rfb_srvr_updt_msg supdt_msg;
312	struct rfb_srvr_rect_hdr srect_hdr;
313	unsigned long zlen;
314	ssize_t nwrite, total;
315	int err;
316	uint32_t *p;
317	uint8_t *zbufp;
318
319	/*
320	 * Send a single rectangle of the given x, y, w h dimensions.
321	 */
322
323	/* Number of rectangles: 1 */
324	supdt_msg.type = 0;
325	supdt_msg.pad = 0;
326	supdt_msg.numrects = htons(1);
327	nwrite = stream_write(cfd, &supdt_msg,
328	                      sizeof(struct rfb_srvr_updt_msg));
329	if (nwrite <= 0)
330		return (nwrite);
331
332
333	/* Rectangle header */
334	srect_hdr.x = htons(x);
335	srect_hdr.y = htons(y);
336	srect_hdr.width = htons(w);
337	srect_hdr.height = htons(h);
338
339	h = y + h;
340	w *= sizeof(uint32_t);
341	if (rc->enc_zlib_ok) {
342		zbufp = rc->zbuf;
343		rc->zstream.total_in = 0;
344		rc->zstream.total_out = 0;
345		for (p = &gc->data[y * gc->width + x]; y < h; y++) {
346			rc->zstream.next_in = (Bytef *)p;
347			rc->zstream.avail_in = w;
348			rc->zstream.next_out = (Bytef *)zbufp;
349			rc->zstream.avail_out = RFB_ZLIB_BUFSZ + 16 -
350			                        rc->zstream.total_out;
351			rc->zstream.data_type = Z_BINARY;
352
353			/* Compress with zlib */
354			err = deflate(&rc->zstream, Z_SYNC_FLUSH);
355			if (err != Z_OK) {
356				WPRINTF(("zlib[rect] deflate err: %d\n", err));
357				rc->enc_zlib_ok = false;
358				deflateEnd(&rc->zstream);
359				goto doraw;
360			}
361			zbufp = rc->zbuf + rc->zstream.total_out;
362			p += gc->width;
363		}
364		srect_hdr.encoding = htonl(RFB_ENCODING_ZLIB);
365		nwrite = stream_write(cfd, &srect_hdr,
366		                      sizeof(struct rfb_srvr_rect_hdr));
367		if (nwrite <= 0)
368			return (nwrite);
369
370		zlen = htonl(rc->zstream.total_out);
371		nwrite = stream_write(cfd, &zlen, sizeof(uint32_t));
372		if (nwrite <= 0)
373			return (nwrite);
374		return (stream_write(cfd, rc->zbuf, rc->zstream.total_out));
375	}
376
377doraw:
378
379	total = 0;
380	zbufp = rc->zbuf;
381	for (p = &gc->data[y * gc->width + x]; y < h; y++) {
382		memcpy(zbufp, p, w);
383		zbufp += w;
384		total += w;
385		p += gc->width;
386	}
387
388	srect_hdr.encoding = htonl(RFB_ENCODING_RAW);
389	nwrite = stream_write(cfd, &srect_hdr,
390	                      sizeof(struct rfb_srvr_rect_hdr));
391	if (nwrite <= 0)
392		return (nwrite);
393
394	total = stream_write(cfd, rc->zbuf, total);
395
396	return (total);
397}
398
399static int
400rfb_send_all(struct rfb_softc *rc, int cfd, struct bhyvegc_image *gc)
401{
402	struct rfb_srvr_updt_msg supdt_msg;
403        struct rfb_srvr_rect_hdr srect_hdr;
404	ssize_t nwrite;
405	unsigned long zlen;
406	int err;
407
408	/*
409	 * Send the whole thing
410	 */
411
412	/* Number of rectangles: 1 */
413	supdt_msg.type = 0;
414	supdt_msg.pad = 0;
415	supdt_msg.numrects = htons(1);
416	nwrite = stream_write(cfd, &supdt_msg,
417	                      sizeof(struct rfb_srvr_updt_msg));
418	if (nwrite <= 0)
419		return (nwrite);
420
421	/* Rectangle header */
422	srect_hdr.x = 0;
423	srect_hdr.y = 0;
424	srect_hdr.width = htons(gc->width);
425	srect_hdr.height = htons(gc->height);
426	if (rc->enc_zlib_ok) {
427		rc->zstream.next_in = (Bytef *)gc->data;
428		rc->zstream.avail_in = gc->width * gc->height *
429		                   sizeof(uint32_t);
430		rc->zstream.next_out = (Bytef *)rc->zbuf;
431		rc->zstream.avail_out = RFB_ZLIB_BUFSZ + 16;
432		rc->zstream.data_type = Z_BINARY;
433
434		rc->zstream.total_in = 0;
435		rc->zstream.total_out = 0;
436
437		/* Compress with zlib */
438		err = deflate(&rc->zstream, Z_SYNC_FLUSH);
439		if (err != Z_OK) {
440			WPRINTF(("zlib deflate err: %d\n", err));
441			rc->enc_zlib_ok = false;
442			deflateEnd(&rc->zstream);
443			goto doraw;
444		}
445
446		srect_hdr.encoding = htonl(RFB_ENCODING_ZLIB);
447		nwrite = stream_write(cfd, &srect_hdr,
448		                      sizeof(struct rfb_srvr_rect_hdr));
449		if (nwrite <= 0)
450			return (nwrite);
451
452		zlen = htonl(rc->zstream.total_out);
453		nwrite = stream_write(cfd, &zlen, sizeof(uint32_t));
454		if (nwrite <= 0)
455			return (nwrite);
456		return (stream_write(cfd, rc->zbuf, rc->zstream.total_out));
457	}
458
459doraw:
460	srect_hdr.encoding = htonl(RFB_ENCODING_RAW);
461	nwrite = stream_write(cfd, &srect_hdr,
462	                      sizeof(struct rfb_srvr_rect_hdr));
463	if (nwrite <= 0)
464		return (nwrite);
465
466	nwrite = stream_write(cfd, gc->data,
467	               gc->width * gc->height * sizeof(uint32_t));
468
469	return (nwrite);
470}
471
472#define	PIX_PER_CELL	32
473#define	PIXCELL_SHIFT	5
474#define	PIXCELL_MASK	0x1F
475
476static int
477rfb_send_screen(struct rfb_softc *rc, int cfd, int all)
478{
479	struct bhyvegc_image *gc_image;
480	ssize_t nwrite;
481	int x, y;
482	int celly, cellwidth;
483	int xcells, ycells;
484	int w, h;
485	uint32_t *p;
486	int rem_x, rem_y;   /* remainder for resolutions not x32 pixels ratio */
487	int retval;
488	uint32_t *crc_p, *orig_crc;
489	int changes;
490
491	console_refresh();
492	gc_image = console_get_image();
493
494	pthread_mutex_lock(&rc->mtx);
495	if (rc->sending) {
496		pthread_mutex_unlock(&rc->mtx);
497		return (1);
498	}
499	rc->sending = 1;
500	pthread_mutex_unlock(&rc->mtx);
501
502	retval = 0;
503
504	if (all) {
505		retval = rfb_send_all(rc, cfd, gc_image);
506		goto done;
507	}
508
509	/*
510	 * Calculate the checksum for each 32x32 cell. Send each that
511	 * has changed since the last scan.
512	 */
513
514	/* Resolution changed */
515
516	rc->crc_width = gc_image->width;
517	rc->crc_height = gc_image->height;
518
519	w = rc->crc_width;
520	h = rc->crc_height;
521	xcells = howmany(rc->crc_width, PIX_PER_CELL);
522	ycells = howmany(rc->crc_height, PIX_PER_CELL);
523
524	rem_x = w & PIXCELL_MASK;
525
526	rem_y = h & PIXCELL_MASK;
527	if (!rem_y)
528		rem_y = PIX_PER_CELL;
529
530	p = gc_image->data;
531
532	/*
533	 * Go through all cells and calculate crc. If significant number
534	 * of changes, then send entire screen.
535	 * crc_tmp is dual purpose: to store the new crc and to flag as
536	 * a cell that has changed.
537	 */
538	crc_p = rc->crc_tmp - xcells;
539	orig_crc = rc->crc - xcells;
540	changes = 0;
541	memset(rc->crc_tmp, 0, sizeof(uint32_t) * xcells * ycells);
542	for (y = 0; y < h; y++) {
543		if ((y & PIXCELL_MASK) == 0) {
544			crc_p += xcells;
545			orig_crc += xcells;
546		}
547
548		for (x = 0; x < xcells; x++) {
549			if (x == (xcells - 1) && rem_x > 0)
550				cellwidth = rem_x;
551			else
552				cellwidth = PIX_PER_CELL;
553
554			if (rc->hw_crc)
555				crc_p[x] = fast_crc32(p,
556				             cellwidth * sizeof(uint32_t),
557				             crc_p[x]);
558			else
559				crc_p[x] = (uint32_t)crc32(crc_p[x],
560				             (Bytef *)p,
561				             cellwidth * sizeof(uint32_t));
562
563			p += cellwidth;
564
565			/* check for crc delta if last row in cell */
566			if ((y & PIXCELL_MASK) == PIXCELL_MASK || y == (h-1)) {
567				if (orig_crc[x] != crc_p[x]) {
568					orig_crc[x] = crc_p[x];
569					crc_p[x] = 1;
570					changes++;
571				} else {
572					crc_p[x] = 0;
573				}
574			}
575		}
576	}
577
578	/* If number of changes is > THRESH percent, send the whole screen */
579	if (((changes * 100) / (xcells * ycells)) >= RFB_SEND_ALL_THRESH) {
580		retval = rfb_send_all(rc, cfd, gc_image);
581		goto done;
582	}
583
584	/* Go through all cells, and send only changed ones */
585	crc_p = rc->crc_tmp;
586	for (y = 0; y < h; y += PIX_PER_CELL) {
587		/* previous cell's row */
588		celly = (y >> PIXCELL_SHIFT);
589
590		/* Delta check crc to previous set */
591		for (x = 0; x < xcells; x++) {
592			if (*crc_p++ == 0)
593				continue;
594
595			if (x == (xcells - 1) && rem_x > 0)
596				cellwidth = rem_x;
597			else
598				cellwidth = PIX_PER_CELL;
599			nwrite = rfb_send_rect(rc, cfd,
600				gc_image,
601				x * PIX_PER_CELL,
602				celly * PIX_PER_CELL,
603			        cellwidth,
604				y + PIX_PER_CELL >= h ? rem_y : PIX_PER_CELL);
605			if (nwrite <= 0) {
606				retval = nwrite;
607				goto done;
608			}
609		}
610	}
611	retval = 1;
612
613done:
614	pthread_mutex_lock(&rc->mtx);
615	rc->sending = 0;
616	pthread_mutex_unlock(&rc->mtx);
617
618	return (retval);
619}
620
621
622static void
623rfb_recv_update_msg(struct rfb_softc *rc, int cfd, int discardonly)
624{
625	struct rfb_updt_msg updt_msg;
626	struct bhyvegc_image *gc_image;
627
628	(void)stream_read(cfd, ((void *)&updt_msg) + 1 , sizeof(updt_msg) - 1);
629
630	console_refresh();
631	gc_image = console_get_image();
632
633	updt_msg.x = htons(updt_msg.x);
634	updt_msg.y = htons(updt_msg.y);
635	updt_msg.width = htons(updt_msg.width);
636	updt_msg.height = htons(updt_msg.height);
637
638	if (updt_msg.width != gc_image->width ||
639	    updt_msg.height != gc_image->height) {
640		rc->width = gc_image->width;
641		rc->height = gc_image->height;
642		if (rc->enc_resize_ok)
643			rfb_send_resize_update_msg(rc, cfd);
644	}
645
646	if (discardonly)
647		return;
648
649	rfb_send_screen(rc, cfd, 1);
650}
651
652static void
653rfb_recv_key_msg(struct rfb_softc *rc, int cfd)
654{
655	struct rfb_key_msg key_msg;
656
657	(void)stream_read(cfd, ((void *)&key_msg) + 1, sizeof(key_msg) - 1);
658
659	console_key_event(key_msg.down, htonl(key_msg.code));
660}
661
662static void
663rfb_recv_ptr_msg(struct rfb_softc *rc, int cfd)
664{
665	struct rfb_ptr_msg ptr_msg;
666
667	(void)stream_read(cfd, ((void *)&ptr_msg) + 1, sizeof(ptr_msg) - 1);
668
669	console_ptr_event(ptr_msg.button, htons(ptr_msg.x), htons(ptr_msg.y));
670}
671
672static void
673rfb_recv_cuttext_msg(struct rfb_softc *rc, int cfd)
674{
675	struct rfb_cuttext_msg ct_msg;
676	unsigned char buf[32];
677	int len;
678
679	len = stream_read(cfd, ((void *)&ct_msg) + 1, sizeof(ct_msg) - 1);
680	ct_msg.length = htonl(ct_msg.length);
681	while (ct_msg.length > 0) {
682		len = stream_read(cfd, buf, ct_msg.length > sizeof(buf) ?
683			sizeof(buf) : ct_msg.length);
684		ct_msg.length -= len;
685	}
686}
687
688static int64_t
689timeval_delta(struct timeval *prev, struct timeval *now)
690{
691	int64_t n1, n2;
692	n1 = now->tv_sec * 1000000 + now->tv_usec;
693	n2 = prev->tv_sec * 1000000 + prev->tv_usec;
694	return (n1 - n2);
695}
696
697static void *
698rfb_wr_thr(void *arg)
699{
700	struct rfb_softc *rc;
701	fd_set rfds;
702	struct timeval tv;
703	struct timeval prev_tv;
704	int64_t tdiff;
705	int cfd;
706	int err;
707
708	rc = arg;
709	cfd = rc->cfd;
710
711	prev_tv.tv_sec = 0;
712	prev_tv.tv_usec = 0;
713	while (rc->cfd >= 0) {
714		FD_ZERO(&rfds);
715		FD_SET(cfd, &rfds);
716		tv.tv_sec = 0;
717		tv.tv_usec = 10000;
718
719		err = select(cfd+1, &rfds, NULL, NULL, &tv);
720		if (err < 0)
721			return (NULL);
722
723		/* Determine if its time to push screen; ~24hz */
724		gettimeofday(&tv, NULL);
725		tdiff = timeval_delta(&prev_tv, &tv);
726		if (tdiff > 40000) {
727			prev_tv.tv_sec = tv.tv_sec;
728			prev_tv.tv_usec = tv.tv_usec;
729			if (rfb_send_screen(rc, cfd, 0) <= 0) {
730				return (NULL);
731			}
732		} else {
733			/* sleep */
734			usleep(40000 - tdiff);
735		}
736	}
737
738	return (NULL);
739}
740
741void
742rfb_handle(struct rfb_softc *rc, int cfd)
743{
744	const char *vbuf = "RFB 003.008\n";
745	unsigned char buf[80];
746	unsigned char *message = NULL;
747
748#ifndef NO_OPENSSL
749	unsigned char challenge[AUTH_LENGTH];
750	unsigned char keystr[PASSWD_LENGTH];
751	unsigned char crypt_expected[AUTH_LENGTH];
752
753	DES_key_schedule ks;
754	int i;
755#endif
756
757	pthread_t tid;
758	uint32_t sres = 0;
759	int len;
760	int perror = 1;
761
762	rc->cfd = cfd;
763
764	/* 1a. Send server version */
765	stream_write(cfd, vbuf, strlen(vbuf));
766
767	/* 1b. Read client version */
768	len = read(cfd, buf, sizeof(buf));
769
770	/* 2a. Send security type */
771	buf[0] = 1;
772#ifndef NO_OPENSSL
773	if (rc->password)
774		buf[1] = SECURITY_TYPE_VNC_AUTH;
775	else
776		buf[1] = SECURITY_TYPE_NONE;
777#else
778	buf[1] = SECURITY_TYPE_NONE;
779#endif
780
781	stream_write(cfd, buf, 2);
782
783	/* 2b. Read agreed security type */
784	len = stream_read(cfd, buf, 1);
785
786	/* 2c. Do VNC authentication */
787	switch (buf[0]) {
788	case SECURITY_TYPE_NONE:
789		sres = 0;
790		break;
791	case SECURITY_TYPE_VNC_AUTH:
792		/*
793		 * The client encrypts the challenge with DES, using a password
794		 * supplied by the user as the key.
795		 * To form the key, the password is truncated to
796		 * eight characters, or padded with null bytes on the right.
797		 * The client then sends the resulting 16-bytes response.
798		 */
799#ifndef NO_OPENSSL
800		strncpy(keystr, rc->password, PASSWD_LENGTH);
801
802		/* VNC clients encrypts the challenge with all the bit fields
803		 * in each byte of the password mirrored.
804		 * Here we flip each byte of the keystr.
805		 */
806		for (i = 0; i < PASSWD_LENGTH; i++) {
807			keystr[i] = (keystr[i] & 0xF0) >> 4
808				  | (keystr[i] & 0x0F) << 4;
809			keystr[i] = (keystr[i] & 0xCC) >> 2
810				  | (keystr[i] & 0x33) << 2;
811			keystr[i] = (keystr[i] & 0xAA) >> 1
812				  | (keystr[i] & 0x55) << 1;
813		}
814
815		/* Initialize a 16-byte random challenge */
816		arc4random_buf(challenge, sizeof(challenge));
817		stream_write(cfd, challenge, AUTH_LENGTH);
818
819		/* Receive the 16-byte challenge response */
820		stream_read(cfd, buf, AUTH_LENGTH);
821
822		memcpy(crypt_expected, challenge, AUTH_LENGTH);
823
824		/* Encrypt the Challenge with DES */
825		DES_set_key((const_DES_cblock *)keystr, &ks);
826		DES_ecb_encrypt((const_DES_cblock *)challenge,
827				(const_DES_cblock *)crypt_expected,
828				&ks, DES_ENCRYPT);
829		DES_ecb_encrypt((const_DES_cblock *)(challenge + PASSWD_LENGTH),
830				(const_DES_cblock *)(crypt_expected +
831				PASSWD_LENGTH),
832				&ks, DES_ENCRYPT);
833
834		if (memcmp(crypt_expected, buf, AUTH_LENGTH) != 0) {
835			message = "Auth Failed: Invalid Password.";
836			sres = htonl(1);
837		} else
838			sres = 0;
839#else
840		sres = 0;
841		WPRINTF(("Auth not supported, no OpenSSL in your system"));
842#endif
843
844		break;
845	}
846
847	/* 2d. Write back a status */
848	stream_write(cfd, &sres, 4);
849
850	if (sres) {
851		be32enc(buf, strlen(message));
852		stream_write(cfd, buf, 4);
853		stream_write(cfd, message, strlen(message));
854		goto done;
855	}
856
857	/* 3a. Read client shared-flag byte */
858	len = stream_read(cfd, buf, 1);
859
860	/* 4a. Write server-init info */
861	rfb_send_server_init_msg(cfd);
862
863	if (!rc->zbuf) {
864		rc->zbuf = malloc(RFB_ZLIB_BUFSZ + 16);
865		assert(rc->zbuf != NULL);
866	}
867
868	rfb_send_screen(rc, cfd, 1);
869
870	perror = pthread_create(&tid, NULL, rfb_wr_thr, rc);
871	if (perror == 0)
872		pthread_set_name_np(tid, "rfbout");
873
874        /* Now read in client requests. 1st byte identifies type */
875	for (;;) {
876		len = read(cfd, buf, 1);
877		if (len <= 0) {
878			DPRINTF(("rfb client exiting\r\n"));
879			break;
880		}
881
882		switch (buf[0]) {
883		case 0:
884			rfb_recv_set_pixfmt_msg(rc, cfd);
885			break;
886		case 2:
887			rfb_recv_set_encodings_msg(rc, cfd);
888			break;
889		case 3:
890			rfb_recv_update_msg(rc, cfd, 1);
891			break;
892		case 4:
893			rfb_recv_key_msg(rc, cfd);
894			break;
895		case 5:
896			rfb_recv_ptr_msg(rc, cfd);
897			break;
898		case 6:
899			rfb_recv_cuttext_msg(rc, cfd);
900			break;
901		default:
902			WPRINTF(("rfb unknown cli-code %d!\n", buf[0] & 0xff));
903			goto done;
904		}
905	}
906done:
907	rc->cfd = -1;
908	if (perror == 0)
909		pthread_join(tid, NULL);
910	if (rc->enc_zlib_ok)
911		deflateEnd(&rc->zstream);
912}
913
914static void *
915rfb_thr(void *arg)
916{
917	struct rfb_softc *rc;
918	sigset_t set;
919
920	int cfd;
921
922	rc = arg;
923
924	sigemptyset(&set);
925	sigaddset(&set, SIGPIPE);
926	if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) {
927		perror("pthread_sigmask");
928		return (NULL);
929	}
930
931	for (;;) {
932		rc->enc_raw_ok = false;
933		rc->enc_zlib_ok = false;
934		rc->enc_resize_ok = false;
935
936		cfd = accept(rc->sfd, NULL, NULL);
937		if (rc->conn_wait) {
938			pthread_mutex_lock(&rc->mtx);
939			pthread_cond_signal(&rc->cond);
940			pthread_mutex_unlock(&rc->mtx);
941			rc->conn_wait = 0;
942		}
943		rfb_handle(rc, cfd);
944		close(cfd);
945	}
946
947	/* NOTREACHED */
948	return (NULL);
949}
950
951static int
952sse42_supported(void)
953{
954	u_int cpu_registers[4], ecx;
955
956	do_cpuid(1, cpu_registers);
957
958	ecx = cpu_registers[2];
959
960	return ((ecx & CPUID2_SSE42) != 0);
961}
962
963int
964rfb_init(char *hostname, int port, int wait, char *password)
965{
966	int e;
967	char servname[6];
968	struct rfb_softc *rc;
969	struct addrinfo *ai;
970	struct addrinfo hints;
971	int on = 1;
972#ifndef WITHOUT_CAPSICUM
973	cap_rights_t rights;
974#endif
975
976	rc = calloc(1, sizeof(struct rfb_softc));
977
978	rc->crc = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32),
979	                 sizeof(uint32_t));
980	rc->crc_tmp = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32),
981	                     sizeof(uint32_t));
982	rc->crc_width = RFB_MAX_WIDTH;
983	rc->crc_height = RFB_MAX_HEIGHT;
984
985	rc->password = password;
986
987	snprintf(servname, sizeof(servname), "%d", port ? port : 5900);
988
989	if (!hostname || strlen(hostname) == 0)
990#if defined(INET)
991		hostname = "127.0.0.1";
992#elif defined(INET6)
993		hostname = "[::1]";
994#endif
995
996	memset(&hints, 0, sizeof(hints));
997	hints.ai_family = AF_UNSPEC;
998	hints.ai_socktype = SOCK_STREAM;
999	hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE;
1000
1001	if ((e = getaddrinfo(hostname, servname, &hints, &ai)) != 0) {
1002		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(e));
1003		return(-1);
1004	}
1005
1006	rc->sfd = socket(ai->ai_family, ai->ai_socktype, 0);
1007	if (rc->sfd < 0) {
1008		perror("socket");
1009		freeaddrinfo(ai);
1010		return (-1);
1011	}
1012
1013	setsockopt(rc->sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1014
1015	if (bind(rc->sfd, ai->ai_addr, ai->ai_addrlen) < 0) {
1016		perror("bind");
1017		freeaddrinfo(ai);
1018		return (-1);
1019	}
1020
1021	if (listen(rc->sfd, 1) < 0) {
1022		perror("listen");
1023		freeaddrinfo(ai);
1024		return (-1);
1025	}
1026
1027#ifndef WITHOUT_CAPSICUM
1028	cap_rights_init(&rights, CAP_ACCEPT, CAP_EVENT, CAP_READ, CAP_WRITE);
1029	if (cap_rights_limit(rc->sfd, &rights) == -1 && errno != ENOSYS)
1030		errx(EX_OSERR, "Unable to apply rights for sandbox");
1031#endif
1032
1033	rc->hw_crc = sse42_supported();
1034
1035	rc->conn_wait = wait;
1036	if (wait) {
1037		pthread_mutex_init(&rc->mtx, NULL);
1038		pthread_cond_init(&rc->cond, NULL);
1039	}
1040
1041	pthread_create(&rc->tid, NULL, rfb_thr, rc);
1042	pthread_set_name_np(rc->tid, "rfb");
1043
1044	if (wait) {
1045		DPRINTF(("Waiting for rfb client...\n"));
1046		pthread_mutex_lock(&rc->mtx);
1047		pthread_cond_wait(&rc->cond, &rc->mtx);
1048		pthread_mutex_unlock(&rc->mtx);
1049	}
1050
1051	freeaddrinfo(ai);
1052	return (0);
1053}
1054